implemented allowance comments in the example / correct display of line is still WIP
Gitea Actions For prodir / Explore-Gitea-Actions (push) Failing after 0s
Details
Gitea Actions For prodir / Explore-Gitea-Actions (push) Failing after 0s
Details
This commit is contained in:
parent
9b4742334a
commit
1a3f6cb451
|
@ -1,5 +1,5 @@
|
||||||
#include "tree_structurer.hpp"
|
#include "tree_structurer.hpp"
|
||||||
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -123,62 +123,166 @@ std::vector<fs::path> TreeStructurer::get_filtered_paths(const fs::path& start)
|
||||||
|
|
||||||
std::vector<std::string> TreeStructurer::get_directory_structure(const std::string& startpath) {
|
std::vector<std::string> TreeStructurer::get_directory_structure(const std::string& startpath) {
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
|
|
||||||
// Normalize the input path by removing ./ or .\ prefix if present
|
// Normalize the input path by removing ./ or .\ prefix if present
|
||||||
std::string normalized_path = startpath;
|
std::string normalized_path = startpath;
|
||||||
if (startpath.substr(0, 2) == ".\\" || startpath.substr(0, 2) == "./") {
|
if (normalized_path.size() >= 2 &&
|
||||||
normalized_path = startpath.substr(2);
|
(normalized_path.substr(0, 2) == ".\\" || normalized_path.substr(0, 2) == "./")) {
|
||||||
|
normalized_path = normalized_path.substr(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path start = normalized_path.empty() ? fs::current_path() : fs::path(normalized_path);
|
fs::path start = normalized_path.empty() ? fs::current_path() : fs::path(normalized_path);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto paths = get_filtered_paths(start);
|
if (!fs::exists(start)) {
|
||||||
if (paths.empty()) {
|
throw std::runtime_error("Directory does not exist: " + start.string());
|
||||||
throw std::runtime_error("No valid files or directories found in: " + start.string());
|
|
||||||
}
|
}
|
||||||
std::vector<bool> is_last_at_level(256, false);
|
|
||||||
|
|
||||||
for (size_t i = 1; i < paths.size(); ++i) {
|
if (!fs::is_directory(start)) {
|
||||||
const auto& path = paths[i];
|
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 + "/");
|
||||||
|
|
||||||
|
// First, collect all paths and organize them by their parent directories
|
||||||
|
std::map<std::string, std::vector<fs::path>> dir_contents;
|
||||||
|
std::vector<std::string> 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);
|
std::string rel_path = get_relative_path(path, start);
|
||||||
|
|
||||||
int level = std::count(rel_path.begin(), rel_path.end(), fs::path::preferred_separator);
|
// Replace backslashes with forward slashes
|
||||||
|
std::replace(rel_path.begin(), rel_path.end(), '\\', '/');
|
||||||
bool is_last = true;
|
|
||||||
for (size_t j = i + 1; j < paths.size(); ++j) {
|
// Skip if it should be ignored
|
||||||
std::string next_rel_path = get_relative_path(paths[j], start);
|
bool should_skip = false;
|
||||||
int next_level = std::count(next_rel_path.begin(), next_rel_path.end(), fs::path::preferred_separator);
|
for (const auto& component : path) {
|
||||||
if (next_level == level) {
|
if (should_ignore_dir(component.string())) {
|
||||||
is_last = false;
|
should_skip = true;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (next_level < level) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (should_skip) continue;
|
||||||
is_last_at_level[level] = is_last;
|
|
||||||
|
if (entry.is_directory()) {
|
||||||
std::string line;
|
if (should_ignore_dir(path.filename().string())) {
|
||||||
for (int j = 0; j < level; ++j) {
|
continue;
|
||||||
if (j == level - 1) {
|
|
||||||
line += is_last ? "└── " : "├── ";
|
|
||||||
} else {
|
|
||||||
line += is_last_at_level[j] ? " " : "│ ";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 = "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
line += path.filename().string();
|
|
||||||
if (fs::is_directory(path)) {
|
|
||||||
line += "/";
|
|
||||||
}
|
|
||||||
result.push_back(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now create the tree structure
|
||||||
|
std::function<void(const std::string&, const std::string&, std::vector<bool>&)>
|
||||||
|
build_tree = [&](const std::string& dir_path, const std::string& prefix, std::vector<bool>& is_last_stack) {
|
||||||
|
// Sort paths - directories first, then files
|
||||||
|
std::vector<fs::path>& 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
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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 next_prefix = prefix;
|
||||||
|
if (!prefix.empty()) {
|
||||||
|
next_prefix += is_last ? " " : "│ ";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<bool> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start building the tree from the root
|
||||||
|
std::vector<bool> is_last_stack;
|
||||||
|
build_tree("/", "", is_last_stack);
|
||||||
|
|
||||||
} catch (const fs::filesystem_error& e) {
|
} catch (const fs::filesystem_error& e) {
|
||||||
throw std::runtime_error("Failed to access directory: " + std::string(e.what()));
|
throw std::runtime_error("Failed to access directory: " + std::string(e.what()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +510,7 @@ void TreeStructurer::create_file(const fs::path& path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads a structure file into a vector of non-empty lines.
|
// Reads a structure file into a vector of non-empty lines, ignoring comments.
|
||||||
std::vector<std::string> TreeStructurer::read_structure_file(const std::string& filepath) {
|
std::vector<std::string> TreeStructurer::read_structure_file(const std::string& filepath) {
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
// Open file in binary mode to avoid Windows CRLF conversion
|
// Open file in binary mode to avoid Windows CRLF conversion
|
||||||
|
@ -416,16 +520,45 @@ std::vector<std::string> TreeStructurer::read_structure_file(const std::string&
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
||||||
while (std::getline(file, line)) {
|
while (std::getline(file, line)) {
|
||||||
// Remove carriage return if present (Windows files)
|
// Remove carriage return if present (Windows files)
|
||||||
if (!line.empty() && line.back() == '\r') {
|
if (!line.empty() && line.back() == '\r') {
|
||||||
line.pop_back();
|
line.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << "Processing line: " << line << std::endl;
|
||||||
|
|
||||||
|
size_t hash_pos = line.find('#');
|
||||||
|
size_t single_line_comment_pos = line.find("//");
|
||||||
|
size_t multi_line_comment_start_pos = line.find("/*");
|
||||||
|
|
||||||
|
if (hash_pos != std::string::npos) {
|
||||||
|
// Trim the line at the hash comment
|
||||||
|
line = line.substr(0, hash_pos);
|
||||||
|
std::cout << "Trimmed line at hash comment position: " << hash_pos << std::endl;
|
||||||
|
} else if (single_line_comment_pos != std::string::npos) {
|
||||||
|
// Trim the line at the single-line comment
|
||||||
|
line = line.substr(0, single_line_comment_pos);
|
||||||
|
std::cout << "Trimmed line at single-line comment position: " << single_line_comment_pos << std::endl;
|
||||||
|
} else if (multi_line_comment_start_pos != std::string::npos) {
|
||||||
|
// Trim the line at the multi-line comment start
|
||||||
|
line = line.substr(0, multi_line_comment_start_pos);
|
||||||
|
std::cout << "Trimmed line at multi-line comment start position: " << multi_line_comment_start_pos << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove leading and trailing whitespace
|
||||||
|
line.erase(0, line.find_first_not_of(" \t\n\r\f\v"));
|
||||||
|
line.erase(line.find_last_not_of(" \t\n\r\f\v") + 1);
|
||||||
|
|
||||||
if (!line.empty()) {
|
if (!line.empty()) {
|
||||||
lines.push_back(line);
|
lines.push_back(line);
|
||||||
|
std::cout << "Added non-empty line: " << line << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Skipped empty or commented-out line." << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
// Checks the structure for obvious mistakes (e.g. a jump in indentation).
|
// Checks the structure for obvious mistakes (e.g. a jump in indentation).
|
||||||
|
|
Loading…
Reference in New Issue