diff --git a/Cargo.lock b/Cargo.lock index b69f57e..a4be46e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -293,7 +293,7 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "yunodo" -version = "0.1.0" +version = "0.3.0" dependencies = [ "clap", "ring", diff --git a/Cargo.toml b/Cargo.toml index 48a96f7..a219e89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yunodo" -version = "0.1.0" +version = "0.3.0" edition = "2021" [dependencies] diff --git a/src/main.rs b/src/main.rs index ab575ef..20ef23a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,65 @@ +//! This module provides functionality to parse file trees for TODO comments. +//! +//! This tool traverses a directory of files, searching for substrings of "//TODO:" and +//! outputs all instances in a parsable format. +//! +//! # Example +//! +//! ``` +//! use clap::Parser; +//! use std::{io, fs, path::PathBuf}; +//! +//! #[derive(Parser)] +//! #[command(name = "YUNODO")] +//! #[command(version = "0.3.0")] +//! #[command(about = "parse file tree for //TODO: comments", long_about = "parses a directory of files for substrings of //TODO: and outputs all instances in a parsable format")] +//! struct Cli { +//! /// Sets a custom config file +//! #[arg(short, long, value_name = "PATH")] +//! path: Option, +//! #[arg(short, long, value_name = "DEBUG")] +//! debug: Option, +//! } +//! +//! /// Reads files in a given directory and its subdirectories. +//! /// +//! /// # Arguments +//! /// +//! /// * `dir_path` - A string slice representing the path to the directory. +//! /// +//! /// # Returns +//! /// +//! /// A Result containing a vector of tuples where each tuple contains the filename and +//! /// a vector of lines in the file, or an io::Error if an error occurs during file I/O. +//! fn read_files_in_directory(dir_path: &str) -> io::Result)>> { +//! // Function implementation... +//! } +//! +//! fn main() { +//! let cli = Cli::parse(); +//! if let Some(path) = cli.path.as_deref() { +//! let path_string = path.display().to_string(); +//! let mut output_csv_item: String = String::new(); +//! match read_files_in_directory(&path_string.as_str()) { +//! Ok(files_content) => { +//! for (filename, lines) in files_content { +//! // Iterating through lines in each file... +//! } +//! } +//! Err(err) => { +//! eprintln!("Error: {}", err); +//! } +//! } +//! println!("{}", output_csv_item) +//! } +//! } +//! ``` use clap::Parser; -use std::{io,fs,path::PathBuf}; -//TODO: implement mod file_tree; :ODOT// +use std::{io, fs, path::PathBuf}; #[derive(Parser)] #[command(name = "YUNODO")] -#[command(version = "0.1.0")] +#[command(version = "0.3.0")] #[command(about = "parse file tree for //TODO: comments", long_about = "parses a directory of files for substrings of //TODO: and outputs all instances in a parsable format")] struct Cli { /// Sets a custom config file @@ -14,6 +69,16 @@ struct Cli { debug: Option, } +/// Reads files in a given directory and its subdirectories. +/// +/// # Arguments +/// +/// * `dir_path` - A string slice representing the path to the directory. +/// +/// # Returns +/// +/// A Result containing a vector of tuples where each tuple contains the filename and +/// a vector of lines in the file, or an io::Error if an error occurs during file I/O. fn read_files_in_directory(dir_path: &str) -> io::Result)>> { let mut files_content = Vec::new(); let paths = fs::read_dir(dir_path)?; @@ -22,11 +87,13 @@ fn read_files_in_directory(dir_path: &str) -> io::Result = content.lines().map(|s| s.to_string()).collect(); files_content.push((filename, lines)); } else if path.is_dir() { + // If the entry is a directory, recursively call the function to read its content let subdir_path = path.to_string_lossy().into_owned(); let subdir_content = read_files_in_directory(&subdir_path)?; files_content.extend(subdir_content); @@ -50,15 +117,18 @@ fn main() { continue; } + // Variables to track if we are within a string, comment, or signature let mut in_string = false; let mut in_comment = false; - let mut in_signature = false; + let mut _in_signature = false; + // Iterate through each character in the line for (i, c) in line.chars().enumerate() { match c { '"' => in_string = !in_string, '/' if !in_string => { if i + 1 < line.len() && line.chars().nth(i + 1).unwrap() == '/' { + // Check if it's a comment in_comment = true; break; } else if i + 1 < line.len() && line.chars().nth(i + 1).unwrap() == '*' { @@ -66,6 +136,7 @@ fn main() { } } '*' if i + 1 < line.len() && line.chars().nth(i + 1).unwrap() == '/' && in_comment => { + // Check for end of block comment in_comment = false; break; } @@ -74,10 +145,12 @@ fn main() { } if in_comment { - let mut v: Vec<&str> = line.split("//TODO:").collect(); + // Extract TODO comments + let v: Vec<&str> = line.split("//TODO:").collect(); if let Some(last_part) = v.last() { if let Some(end_index) = last_part.find(":ODOT//") { let extracted = &last_part[..end_index]; + // Format output CSV item if !output_csv_item.is_empty(){ output_csv_item = format!("{},path:\"{}\",file_name:\"{}\",line_number:\"{}\",comment:\"{}\"", output_csv_item, path_string, filename, line_number + 1, extracted); } else {