mirror of
https://github.com/archtechx/todo-system.git
synced 2025-12-12 00:54:03 +00:00
Compare commits
3 commits
d4bf97ce12
...
fa9c36bf6d
| Author | SHA1 | Date | |
|---|---|---|---|
| fa9c36bf6d | |||
| 32a57ab5fb | |||
| ea031d81f0 |
4 changed files with 48 additions and 22 deletions
|
|
@ -195,6 +195,14 @@ 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"
|
||||||
|
|
|
||||||
10
src/main.rs
10
src/main.rs
|
|
@ -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};
|
use crate::scan::{Stats, scan_dir, scan_todo_file, scan_readme_file, Exclude};
|
||||||
|
|
||||||
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<PathBuf> = vec![];
|
let mut excludes: Vec<Exclude> = 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(realpath);
|
excludes.push(Exclude::Path(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(todos_path.clone());
|
excludes.push(Exclude::Path(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(readme_path.clone());
|
excludes.push(Exclude::Path(readme_path.clone()));
|
||||||
|
|
||||||
scan_readme_file(&readme_path, &mut entries).unwrap();
|
scan_readme_file(&readme_path, &mut entries).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ 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();
|
||||||
|
|
||||||
|
|
@ -121,5 +122,5 @@ pub fn render_entries(entries: Vec<Entry>) {
|
||||||
for item in generic_entries {
|
for item in generic_entries {
|
||||||
item.render();
|
item.render();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
src/scan.rs
39
src/scan.rs
|
|
@ -1,12 +1,27 @@
|
||||||
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::glob;
|
use glob::{Pattern};
|
||||||
|
|
||||||
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,
|
||||||
|
|
@ -100,7 +115,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<PathBuf>) {
|
pub fn add_excludes_from_gitignore(base_dir: &PathBuf, excludes: &mut Vec<Exclude>) {
|
||||||
let mut gitignore = base_dir.clone();
|
let mut gitignore = base_dir.clone();
|
||||||
gitignore.push(".gitignore");
|
gitignore.push(".gitignore");
|
||||||
|
|
||||||
|
|
@ -115,7 +130,7 @@ pub fn add_excludes_from_gitignore(base_dir: &PathBuf, excludes: &mut Vec<PathBu
|
||||||
|
|
||||||
if line.trim() == "*" {
|
if line.trim() == "*" {
|
||||||
if let Ok(realpath) = canonicalize(base_dir) {
|
if let Ok(realpath) = canonicalize(base_dir) {
|
||||||
excludes.push(realpath);
|
excludes.push(Exclude::Path(realpath));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -132,12 +147,14 @@ pub fn add_excludes_from_gitignore(base_dir: &PathBuf, excludes: &mut Vec<PathBu
|
||||||
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 let Some(pattern_str) = pattern.to_str() {
|
if pattern.to_str().unwrap().contains('*') {
|
||||||
for path in glob(pattern_str).unwrap() {
|
if let Some(str) = pattern.to_str() {
|
||||||
if let Ok(exclude) = canonicalize(path.unwrap()) {
|
if let Ok(p) = Pattern::new(str) {
|
||||||
excludes.push(exclude);
|
excludes.push(Exclude::Glob(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
excludes.push(Exclude::Path(pattern));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -226,7 +243,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<PathBuf>, stats: &mut Stats) -> io::Result<()> {
|
pub fn scan_dir(dir: &Path, entries: &mut Vec<Entry>, excludes: &mut Vec<Exclude>, 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");
|
||||||
|
|
||||||
|
|
@ -234,11 +251,11 @@ pub fn scan_dir(dir: &Path, entries: &mut Vec<Entry>, excludes: &mut Vec<PathBuf
|
||||||
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. Tthe directory is visited first, and gitignore is read second,
|
// e.g. if it contains a `*` line. The 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 canonicalize(dir).unwrap() == *exclude {
|
if Exclude::Path(canonicalize(dir).unwrap()) == *exclude {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -255,7 +272,7 @@ pub fn scan_dir(dir: &Path, entries: &mut Vec<Entry>, excludes: &mut Vec<PathBuf
|
||||||
}
|
}
|
||||||
|
|
||||||
for exclude in &*excludes {
|
for exclude in &*excludes {
|
||||||
if canonicalize(&path).unwrap() == *exclude {
|
if exclude.matches(&path) {
|
||||||
continue 'entry;
|
continue 'entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue