1
0
Fork 0
mirror of https://github.com/archtechx/todo-system.git synced 2025-12-12 09:04:03 +00:00

CLI arg parsing

This commit is contained in:
Samuel Štancl 2023-11-22 02:32:35 +01:00
parent 15c2c7d3f0
commit 574cee8895
4 changed files with 318 additions and 27 deletions

216
Cargo.lock generated
View file

@ -2,6 +2,222 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "anstream"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "anstyle-parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "clap"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "proc-macro2"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "todo-system" name = "todo-system"
version = "0.1.0" version = "0.1.0"
dependencies = [
"clap",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

View file

@ -2,7 +2,10 @@
name = "todo-system" name = "todo-system"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
authors = ["Samuel Štancl <samuel@archte.ch>"]
description = "An intuitive system for organizing TODOs in code"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
clap = { version = "4.4.8", features = ["derive"] }

View file

@ -99,7 +99,7 @@ That said, this repo includes a simple CLI tool written in Rust for getting an e
Usage: Usage:
``` ```
todos src/ todos --exclude node_modules src/
``` ```
Output: Output:
@ -131,3 +131,8 @@ Output:
``` ```
(without the HTML comments). (without the HTML comments).
Notes:
- `node_modules/` (for npm) and `vendor/` (for composer) are ignored by default
- paths starting with `.` are **always** ignored
- `--exclude`s are relative to the current working directory, not passed paths (including default excludes mentioned above). If you're running the script for another folder and want to exclude folders there, type out the path in `--exclude`

View file

@ -1,6 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::{io, fs}; use std::{io, fs};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use clap::Parser;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
struct Location { struct Location {
@ -32,6 +33,25 @@ impl Entry {
} }
} }
struct Stats {
visited_folders: usize,
visited_files: usize,
}
impl Stats {
fn new() -> Stats {
Stats {
visited_folders: 0,
visited_files: 0,
}
}
fn print(&self) {
eprintln!("[INFO] Visited folders: {}", self.visited_folders);
eprintln!("[INFO] Visited files: {}", self.visited_files);
}
}
fn scan_string(str: String, filename: PathBuf, entries: &mut Vec<Entry>) { fn scan_string(str: String, filename: PathBuf, entries: &mut Vec<Entry>) {
for (line_num, line) in str.lines().enumerate() { for (line_num, line) in str.lines().enumerate() {
if ! line.to_lowercase().contains("todo") { if ! line.to_lowercase().contains("todo") {
@ -44,7 +64,7 @@ fn scan_string(str: String, filename: PathBuf, entries: &mut Vec<Entry>) {
} }
// Handles: `todo`, `TODO`, `todo:`, `TODO:` // Handles: `todo`, `TODO`, `todo:`, `TODO:`
// todo `replace` isnt ideal, it should only replace *after* the todo, to avoid merging eg `to:do` // todo@real `replace` isnt ideal, it should only replace *after* the todo, to avoid merging eg `to:do`
if word.to_lowercase().replace(':', "") == "todo" { if word.to_lowercase().replace(':', "") == "todo" {
let text_dirty = line.split_once(word).unwrap().1.replace("*/", ""); let text_dirty = line.split_once(word).unwrap().1.replace("*/", "");
let text = text_dirty.trim(); let text = text_dirty.trim();
@ -113,7 +133,6 @@ fn scan_string(str: String, filename: PathBuf, entries: &mut Vec<Entry>) {
} }
} }
// todo test this using sample.ts
fn scan_file(path: &Path, entries: &mut Vec<Entry>) -> io::Result<()> { fn scan_file(path: &Path, entries: &mut Vec<Entry>) -> io::Result<()> {
match std::fs::read_to_string(path) { match std::fs::read_to_string(path) {
Ok(str) => scan_string(str, path.to_path_buf(), entries), Ok(str) => scan_string(str, path.to_path_buf(), entries),
@ -123,27 +142,27 @@ fn scan_file(path: &Path, entries: &mut Vec<Entry>) -> io::Result<()> {
Ok(()) Ok(())
} }
fn scan_dir(path: &Path, entries: &mut Vec<Entry>) -> io::Result<()> { fn scan_dir(path: &Path, entries: &mut Vec<Entry>, excludes: &Vec<PathBuf>, stats: &mut Stats) -> io::Result<()> {
for entry in fs::read_dir(path)? { stats.visited_folders += 1;
'entry: for entry in fs::read_dir(path)? {
let entry = entry?; let entry = entry?;
let path = entry.path(); let path = entry.path();
if path.components().last().unwrap().as_os_str().to_string_lossy().starts_with('.') {
continue;
}
if path.is_dir() { if path.is_dir() {
// todo make these configurable for exclude in excludes {
if path.ends_with("node_modules") { if path == *exclude {
continue; continue 'entry;
}
} }
if path.ends_with("vendor") { scan_dir(path.as_path(), entries, excludes, stats)?
continue;
}
if path.ends_with(".git") {
continue;
}
scan_dir(path.as_path(), entries)?
} else { } else {
stats.visited_files += 1;
scan_file(path.as_path(), entries)? scan_file(path.as_path(), entries)?
} }
} }
@ -233,21 +252,66 @@ fn render(entries: Vec<Entry>) {
} }
fn main() { #[derive(Parser, Debug)]
let args = std::env::args(); #[command(author, version, about, long_about = None)]
let mut root_dir: PathBuf = std::env::current_dir().unwrap(); struct Args {
/// Path to your README.md file
#[arg(short, long, default_value = "")]
readme: String,
if args.len() > 1 { // Path to your todo.md file
for arg in args.skip(1) { #[arg(short, long, default_value = "")]
root_dir.push(arg); todos: String,
}
// Paths to search
#[arg(default_values_t = Vec::from([".".to_string()]))]
paths: Vec<String>,
// Paths to exclude
#[arg(short, long, default_values_t = Vec::from([
"node_modules".to_string(),
"vendor".to_string(),
]))]
exclude: Vec<String>,
#[arg(short, long, default_value_t = false)]
verbose: bool,
}
fn main() {
let args = Args::parse();
let root_dir: PathBuf = std::env::current_dir().unwrap();
let mut paths: Vec<PathBuf> = vec![];
let mut excludes: Vec<PathBuf> = vec![];
for p in args.paths {
let mut path = root_dir.clone();
path.push(p);
paths.push(path);
} }
let mut entries: Vec<Entry> = vec![]; for exclude in args.exclude {
let mut path = root_dir.clone();
path.push(exclude);
scan_dir(root_dir.as_path(), &mut entries).unwrap(); excludes.push(path);
}
// todo@real logic for readme.md and todos.md
let mut entries: Vec<Entry> = vec![];
let mut stats = Stats::new();
scan_dir(root_dir.as_path(), &mut entries, &excludes, &mut stats).unwrap();
render(entries); render(entries);
if args.verbose {
eprint!("\n\n");
stats.print();
}
} }
#[test] #[test]
@ -515,7 +579,10 @@ fn sample_test_ts() {
let mut filepath = path.clone(); let mut filepath = path.clone();
filepath.push("1.ts"); filepath.push("1.ts");
scan_dir(path.as_path(), &mut entries).unwrap(); let excludes: Vec<PathBuf> = vec![];
let mut stats = Stats::new();
scan_dir(path.as_path(), &mut entries, &excludes, &mut stats).unwrap();
assert_eq!(10, entries.len()); assert_eq!(10, entries.len());