diff --git a/setup.py b/setup.py index 264db61..576a701 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ tree_structurer_module = Extension( setup( name='tree_structurer', - version='0.0.4', + version='0.0.5', description='A module for analyzing directory structures', ext_modules=[tree_structurer_module], packages=['tree_structurer'], diff --git a/tree_structurer/__main__.py b/tree_structurer/__main__.py index cb5c6d4..ba5c985 100644 --- a/tree_structurer/__main__.py +++ b/tree_structurer/__main__.py @@ -17,6 +17,7 @@ def main(): create_tree_structurer() # Get and print structure directly structure = get_structure(args.path) + print(f"dir Structure for {args.path}:") for line in structure: print(line) diff --git a/tree_structurer/cpp/tree_structurer.cpp b/tree_structurer/cpp/tree_structurer.cpp index a2af3cb..db3834d 100644 --- a/tree_structurer/cpp/tree_structurer.cpp +++ b/tree_structurer/cpp/tree_structurer.cpp @@ -3,18 +3,17 @@ #include namespace fs = std::filesystem; + bool TreeStructurer::should_ignore_dir(const std::string& dirname) { static const std::vector ignore_list = { "build", "venv", "myenv", "dist", "node_modules", "CMakeFiles", ".git", ".idea", ".vscode", "__pycache__" }; - // Ignore directories in the ignore list if (std::find(ignore_list.begin(), ignore_list.end(), dirname) != ignore_list.end()) { return true; } - // Ignore directories starting with '.' or '_' if (!dirname.empty() && (dirname[0] == '.' || dirname[0] == '_')) { return true; } @@ -28,12 +27,10 @@ bool TreeStructurer::should_ignore_file(const std::string& filename) { ".o", ".obj", ".a", ".lib" }; - // Ignore files starting with '.' or '_' if (!filename.empty() && (filename[0] == '.' || filename[0] == '_')) { return true; } - // Ignore files with specific extensions fs::path path(filename); std::string ext = path.extension().string(); if (std::find(ignore_extensions.begin(), ignore_extensions.end(), ext) != ignore_extensions.end()) { @@ -45,55 +42,44 @@ bool TreeStructurer::should_ignore_file(const std::string& filename) { std::vector TreeStructurer::get_filtered_paths(const fs::path& start) { std::vector paths; + fs::directory_options options = fs::directory_options::skip_permission_denied; - for (const auto& entry : fs::recursive_directory_iterator(start)) { - const auto& path = entry.path(); + try { + if (fs::exists(start) && fs::is_directory(start)) { + paths.push_back(start); - // Skip any path that contains an ignored directory - bool contains_ignored_dir = false; - for (auto it = path.begin(); it != path.end(); ++it) { - if (should_ignore_dir(it->string())) { - contains_ignored_dir = true; - break; - } - } - - if (contains_ignored_dir) { - continue; - } - - // Handle directories - if (fs::is_directory(path)) { - if (!should_ignore_dir(path.filename().string())) { - paths.push_back(path); - } - } - // Handle files - else { - if (!should_ignore_file(path.filename().string())) { - paths.push_back(path); + for (const auto& entry : fs::recursive_directory_iterator(start, options)) { + const auto& path = entry.path(); + + // Check if any parent directory 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; + + if (entry.is_directory()) { + if (should_ignore_dir(path.filename().string())) { + paths.push_back(path); + } + } else { + if (should_ignore_file(path.filename().string())) { + paths.push_back(path); + } + } } } + } catch (const fs::filesystem_error& e) { + throw std::runtime_error("Error accessing path: " + std::string(e.what())); } std::sort(paths.begin(), paths.end()); return paths; } - - -std::string TreeStructurer::create_indent(int level) { - if (level == 0) return ""; - - std::string indent; - for (int i = 0; i < level - 1; ++i) { - indent += "│ "; - } - indent += "├─ "; - return indent; -} - - std::string TreeStructurer::get_relative_path(const fs::path& path, const fs::path& base) { fs::path rel = fs::relative(path, base); return rel.string(); @@ -102,26 +88,50 @@ std::string TreeStructurer::get_relative_path(const fs::path& path, const fs::pa std::vector TreeStructurer::get_directory_structure(const std::string& startpath) { std::vector result; fs::path start = startpath.empty() ? fs::current_path() : fs::path(startpath); - + try { - result.push_back(start.filename().string() + "/"); - auto paths = get_filtered_paths(start); + if (paths.empty()) return result; + + // Don't add the root directory name if we're in the current directory + if (start != fs::current_path()) { + result.push_back(start.filename().string()); + } + std::vector is_last_at_level(256, false); - - for (size_t i = 0; i < paths.size(); ++i) { + std::string last_prefix; + + for (size_t i = 1; i < paths.size(); ++i) { const auto& path = paths[i]; std::string rel_path = get_relative_path(path, start); + + // Split the path into components and check each component + bool should_skip = false; + for (const auto& component : fs::path(rel_path)) { + if (should_ignore_dir(component.string())) { + should_skip = true; + break; + } + } + if (should_skip) continue; + int level = std::count(rel_path.begin(), rel_path.end(), fs::path::preferred_separator); - - bool is_last = (i == paths.size() - 1) || - (i < paths.size() - 1 && - std::count(get_relative_path(paths[i + 1], start).begin(), - get_relative_path(paths[i + 1], start).end(), - fs::path::preferred_separator) <= level); - + + // Check if this is the last item at this level + bool is_last = false; + for (size_t j = i + 1; j < paths.size(); j++) { + const auto& next_path = paths[j]; + std::string next_rel_path = get_relative_path(next_path, start); + int next_level = std::count(next_rel_path.begin(), next_rel_path.end(), fs::path::preferred_separator); + if (next_level <= level) { + is_last = (j == paths.size() - 1) || (next_level < level); + break; + } + } + if (i == paths.size() - 1) is_last = true; + is_last_at_level[level] = is_last; - + std::string line; for (int j = 0; j < level; ++j) { if (j == level - 1) { @@ -130,9 +140,9 @@ std::vector TreeStructurer::get_directory_structure(const std::stri line += is_last_at_level[j] ? " " : "│ "; } } - + line += path.filename().string(); - if(fs::is_directory(path)) { + if (fs::is_directory(path)) { line += "/"; } result.push_back(line); @@ -140,6 +150,6 @@ std::vector TreeStructurer::get_directory_structure(const std::stri } catch (const fs::filesystem_error& e) { throw std::runtime_error("Failed to access directory: " + std::string(e.what())); } - + return result; -} \ No newline at end of file +}