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

Compare commits

..

No commits in common. "fa9c36bf6da11833199b43d91c878d75d3b154b6" and "d4bf97ce12fa19ca0e18b7c79c32c203f06ae2b0" have entirely different histories.

4 changed files with 22 additions and 48 deletions

View file

@ -195,14 +195,6 @@ There are no downloadable builds at the moment. To compile the tool manually:
2. `cargo install --git https://github.com/archtechx/todo-system.git` 2. `cargo install --git https://github.com/archtechx/todo-system.git`
3. The tool will be added to your `$PATH` automatically as `todos` 3. The tool will be added to your `$PATH` automatically as `todos`
If you use Nix (with flakes), you can use this repo as an input. The tool is
exported as the default package. You can try it out using:
```
nix run github:archtechx/todo-system -- --help
# or create a temporary shell with `todos` in PATH:
nix shell github:archtechx/todo-system
```
I personally also like creating an alias that does `todos | less`: I personally also like creating an alias that does `todos | less`:
```sh ```sh
alias t="todos | less" alias t="todos | less"

View file

@ -4,7 +4,7 @@ use std::path::PathBuf;
use clap::{Parser, ArgAction}; use clap::{Parser, ArgAction};
use crate::entries::Entry; use crate::entries::Entry;
use crate::render::render_entries; use crate::render::render_entries;
use crate::scan::{Stats, scan_dir, scan_todo_file, scan_readme_file, Exclude}; use crate::scan::{Stats, scan_dir, scan_todo_file, scan_readme_file};
pub mod scan; pub mod scan;
pub mod render; pub mod render;
@ -43,7 +43,7 @@ fn main() {
let root_dir: PathBuf = std::env::current_dir().unwrap(); let root_dir: PathBuf = std::env::current_dir().unwrap();
let mut paths: Vec<PathBuf> = vec![]; let mut paths: Vec<PathBuf> = vec![];
let mut excludes: Vec<Exclude> = vec![]; let mut excludes: Vec<PathBuf> = vec![];
let mut entries: Vec<Entry> = vec![]; let mut entries: Vec<Entry> = vec![];
let mut stats = Stats::new(args.verbose); let mut stats = Stats::new(args.verbose);
@ -68,7 +68,7 @@ fn main() {
if path.exists() { if path.exists() {
if let Ok(realpath) = canonicalize(path) { if let Ok(realpath) = canonicalize(path) {
excludes.push(Exclude::Path(realpath)); excludes.push(realpath);
} }
} }
} }
@ -80,13 +80,13 @@ fn main() {
readme_path.push(&args.readme); readme_path.push(&args.readme);
if todos_path.exists() { if todos_path.exists() {
excludes.push(Exclude::Path(todos_path.clone())); excludes.push(todos_path.clone());
scan_todo_file(&todos_path, &mut entries).unwrap(); scan_todo_file(&todos_path, &mut entries).unwrap();
} }
if readme_path.exists() { if readme_path.exists() {
excludes.push(Exclude::Path(readme_path.clone())); excludes.push(readme_path.clone());
scan_readme_file(&readme_path, &mut entries).unwrap(); scan_readme_file(&readme_path, &mut entries).unwrap();
} }

View file

@ -113,14 +113,13 @@ pub fn render_entries(entries: Vec<Entry>) {
println!(); println!();
} }
if generic_entries.len() > 0 { write_ansi(&mut stdout, Color::White, "## Other", true);
write_ansi(&mut stdout, Color::White, "## Other", true); writeln!(stdout).unwrap();
writeln!(stdout).unwrap();
generic_entries.sort_by(|a, b| a.text.partial_cmp(&b.text).unwrap()); generic_entries.sort_by(|a, b| a.text.partial_cmp(&b.text).unwrap());
for item in generic_entries { for item in generic_entries {
item.render(); item.render();
}
} }
} }

View file

@ -1,27 +1,12 @@
use std::io; use std::io;
use std::fs::{self, canonicalize}; use std::fs::{self, canonicalize};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use glob::{Pattern}; use glob::glob;
const PRIORITY_CHARS: [char; 10] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; const PRIORITY_CHARS: [char; 10] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
use crate::entries::{Entry, EntryData, Location}; use crate::entries::{Entry, EntryData, Location};
#[derive(Debug, PartialEq, Eq)]
pub enum Exclude {
Path(PathBuf),
Glob(Pattern),
}
impl Exclude {
pub fn matches(&self, path: &Path) -> bool {
match self {
Exclude::Path(p) => p == path,
Exclude::Glob(g) => g.matches_path(path),
}
}
}
pub struct Stats { pub struct Stats {
visited_folder_count: usize, visited_folder_count: usize,
visited_file_count: usize, visited_file_count: usize,
@ -115,7 +100,7 @@ fn clean_line<'a>(line: &'a str, delimiter_word: &str) -> &'a str {
.trim() .trim()
} }
pub fn add_excludes_from_gitignore(base_dir: &PathBuf, excludes: &mut Vec<Exclude>) { pub fn add_excludes_from_gitignore(base_dir: &PathBuf, excludes: &mut Vec<PathBuf>) {
let mut gitignore = base_dir.clone(); let mut gitignore = base_dir.clone();
gitignore.push(".gitignore"); gitignore.push(".gitignore");
@ -130,7 +115,7 @@ pub fn add_excludes_from_gitignore(base_dir: &PathBuf, excludes: &mut Vec<Exclud
if line.trim() == "*" { if line.trim() == "*" {
if let Ok(realpath) = canonicalize(base_dir) { if let Ok(realpath) = canonicalize(base_dir) {
excludes.push(Exclude::Path(realpath)); excludes.push(realpath);
} }
break; break;
@ -147,14 +132,12 @@ pub fn add_excludes_from_gitignore(base_dir: &PathBuf, excludes: &mut Vec<Exclud
let mut pattern = base_dir.clone(); let mut pattern = base_dir.clone();
pattern.push(line.trim_end_matches("*/").trim_matches('/')); pattern.push(line.trim_end_matches("*/").trim_matches('/'));
if pattern.to_str().unwrap().contains('*') { if let Some(pattern_str) = pattern.to_str() {
if let Some(str) = pattern.to_str() { for path in glob(pattern_str).unwrap() {
if let Ok(p) = Pattern::new(str) { if let Ok(exclude) = canonicalize(path.unwrap()) {
excludes.push(Exclude::Glob(p)); excludes.push(exclude);
} }
} }
} else {
excludes.push(Exclude::Path(pattern));
} }
} }
} }
@ -243,7 +226,7 @@ pub fn scan_file(path: &Path, entries: &mut Vec<Entry>) -> io::Result<()> {
Ok(()) Ok(())
} }
pub fn scan_dir(dir: &Path, entries: &mut Vec<Entry>, excludes: &mut Vec<Exclude>, stats: &mut Stats) -> io::Result<()> { pub fn scan_dir(dir: &Path, entries: &mut Vec<Entry>, excludes: &mut Vec<PathBuf>, stats: &mut Stats) -> io::Result<()> {
let mut gitignore = dir.to_path_buf().clone(); let mut gitignore = dir.to_path_buf().clone();
gitignore.push(".gitignore"); gitignore.push(".gitignore");
@ -251,11 +234,11 @@ pub fn scan_dir(dir: &Path, entries: &mut Vec<Entry>, excludes: &mut Vec<Exclude
add_excludes_from_gitignore(&dir.to_path_buf(), excludes); add_excludes_from_gitignore(&dir.to_path_buf(), excludes);
// `add_excludes_from_gitignore` can add the *entire* directory being scanned here to excludes // `add_excludes_from_gitignore` can add the *entire* directory being scanned here to excludes
// e.g. if it contains a `*` line. The directory is visited first, and gitignore is read second, // e.g. if it contains a `*` line. Tthe directory is visited first, and gitignore is read second,
// so the exclude would not affect anything inside the for loop. For that reason, we re-check if // so the exclude would not affect anything inside the for loop. For that reason, we re-check if
// `dir` hasn't become excluded after running `add_excludes_from_gitignore`. // `dir` hasn't become excluded after running `add_excludes_from_gitignore`.
for exclude in &*excludes { for exclude in &*excludes {
if Exclude::Path(canonicalize(dir).unwrap()) == *exclude { if canonicalize(dir).unwrap() == *exclude {
return Ok(()); return Ok(());
} }
} }
@ -272,7 +255,7 @@ pub fn scan_dir(dir: &Path, entries: &mut Vec<Entry>, excludes: &mut Vec<Exclude
} }
for exclude in &*excludes { for exclude in &*excludes {
if exclude.matches(&path) { if canonicalize(&path).unwrap() == *exclude {
continue 'entry; continue 'entry;
} }
} }