diff --git a/src/cli.rs b/src/cli.rs index ec2b36f..1cba9a1 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -49,7 +49,7 @@ pub enum Commands { Count, /// -> show items in all inboxes - #[clap(visible_aliases(["A", "g"]))] + #[clap(visible_aliases(["g"]))] Glance, /// -> purge all the duplicated lines diff --git a/src/main.rs b/src/main.rs index 7ed6c62..4c93226 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ fn main() { inbox = Some(get_tomorrow()) } - let inbox_path = util::get_inbox_file(args.dir, inbox); + let inbox_path = get_inbox_file(args.dir, inbox); match args.command { Some(Commands::Mark) | None => { @@ -58,14 +58,14 @@ fn main() { println!(" {} left!", "nothing".yellow()); } else { for t in tasks { - println!(" 󰄗 {}", t.bold()) + println!("{} {}", "󰄗".to_string().red(), t) } } if all && !dones.is_empty() { println!(); for t in dones { - println!(" 󰄸 {}", t.strikethrough()) + println!("󰄸 {}", t.strikethrough()) } } } @@ -116,7 +116,7 @@ fn main() { } Some(Commands::Listbox) => { - util::list_boxes(inbox_path.as_path().parent().unwrap()) + TaskBox::list_boxes(inbox_path) } Some(Commands::Purge) => { @@ -130,19 +130,19 @@ fn main() { } Some(Commands::Sink { all }) => { - TaskBox::sink(inbox_path.as_path().parent().unwrap(), all) + TaskBox::sink(inbox_path, all) } Some(Commands::Shift) => { - TaskBox::shift(inbox_path.as_path().parent().unwrap()) + TaskBox::shift(inbox_path) } Some(Commands::Collect) => { - TaskBox::collect(inbox_path.clone().as_path().parent().unwrap(), inbox_path) + TaskBox::collect(inbox_path) } Some(Commands::Postp) => { - TaskBox::postp(inbox_path.clone().as_path().parent().unwrap(), inbox_path) + TaskBox::postp(inbox_path) } Some(Commands::Import{ file }) => { diff --git a/src/taskbox.rs b/src/taskbox.rs index b0f0839..28ed97d 100644 --- a/src/taskbox.rs +++ b/src/taskbox.rs @@ -2,10 +2,25 @@ use std::fs; use std::path::{Path, PathBuf}; use regex::Regex; use colored::Colorize; +use dirs; use chrono::*; use std::ops::*; +const DATA_BASE : &str = ".local/share/todor"; +const INBOX_NAME :&str = "INBOX"; + +pub fn get_inbox_file(dir: Option, inbox: Option) -> PathBuf { + let base_path = dir.map(PathBuf::from).unwrap_or_else(|| { + dirs::home_dir() + .expect("cannot get home directory") + .join(DATA_BASE) + }); + fs::create_dir_all(&base_path).expect("Failed to create base directory"); + + base_path.join(inbox.unwrap_or(INBOX_NAME.to_string())).with_extension("md") +} + pub fn get_today() -> String { Local::now().date_naive().to_string() } @@ -16,6 +31,18 @@ pub fn get_tomorrow() -> String { Local::now().add(chrono::Duration::days(1)).date_naive().to_string() } +fn get_alias(name_in: Option) -> Option { + let alias = match name_in { + Some(name) if name == get_today() => "today", + Some(name) if name == get_tomorrow() => "tomorrow", + Some(name) if name == get_yesterday() => "yesterday", + _ => "", + }; + + if alias.is_empty() { None } + else { Some(alias.to_string()) } +} + const PREFIX :&str = "- [ ] "; const PREFIX_DONE :&str = "- [x] "; @@ -23,6 +50,7 @@ const PREFIX_DONE :&str = "- [x] "; pub struct TaskBox { fpath: PathBuf, title: Option, + alias: Option, tasks: Vec<(String, bool)>, } @@ -38,6 +66,7 @@ impl TaskBox { Self { fpath, title: None, // None means not loaded + alias: get_alias(Some(title)), tasks: Vec::new(), } } @@ -47,22 +76,22 @@ impl TaskBox { return } - let content = fs::read_to_string(&self.fpath).expect("Failed to read file"); let mut tasks = Vec::new(); let mut title = String::new(); - for (index, line) in content.lines().enumerate() { + for (index, rline) in fs::read_to_string(&self.fpath) + .expect("Failed to read file") + .lines().enumerate() { + + let line = rline.trim(); if index == 0 { - title = line.trim().trim_start_matches("# ").to_string(); + title = line.trim_start_matches("# ").to_string(); - } else { - let trimmed = line.trim(); - if trimmed.starts_with("- [") && trimmed.len() > 4 { - let completed = trimmed.chars().nth(3) == Some('x'); - let task = trimmed[5..].trim().to_string(); - tasks.push((task, completed)); - } + } else if let Some(stripped) = line.strip_prefix(PREFIX) { + tasks.push((stripped.to_string(), false)) + } else if let Some(stripped) = line.strip_prefix(PREFIX_DONE) { + tasks.push((stripped.to_string(), true)) } } @@ -101,27 +130,24 @@ impl TaskBox { } fn _move_in(&mut self, todo_in: &mut TaskBox) { - fn __friendly_name(name_in: Option<&String>) -> &str { - if Some(&get_today()) == name_in { - "today" - } else if Some(&get_tomorrow()) == name_in { - "tomorrow" - } else if Some(&get_yesterday()) == name_in { - "yesterday" - } else { - name_in.map(|x| x.as_str()).unwrap() - } - } - self._load(); todo_in._load(); let (tasks, _) = todo_in._list(); if tasks.is_empty() { return } - println!("{}  {} ↩️", - __friendly_name(todo_in.title.as_ref()).green(), - __friendly_name(self.title.as_ref()).blue()); + let from = if todo_in.alias.is_some() { + todo_in.alias.as_ref() + } else { + todo_in.title.as_ref() + }; + let to = if self.alias.is_some() { + self.alias.as_ref() + } else { + self.title.as_ref() + }; + + println!("{}  {} ↩️", from.unwrap().green(), to.unwrap().blue()); for task in tasks { println!("{} : {}", " 󰄗".to_string().red(), task); @@ -203,7 +229,8 @@ impl TaskBox { // outdated -> today // flag:all -- whether sink future (mainly tomorrow) - pub fn sink(basedir: &Path, all: bool) { + pub fn sink(inbox_path: PathBuf, all: bool) { + let basedir = inbox_path.as_path().parent().unwrap(); let mut today_todo = TaskBox::new(basedir.join(get_today()).with_extension("md")); let re = Regex::new(r"\d{4}-\d{2}-\d{2}.md$").unwrap(); @@ -230,24 +257,30 @@ impl TaskBox { } // today -> tomorrow - pub fn shift(basedir: &Path) { + pub fn shift(inbox_path: PathBuf) { + let basedir = inbox_path.as_path().parent().unwrap(); + let mut today_todo = TaskBox::new(basedir.join(get_today()).with_extension("md")); let mut tomor_todo = TaskBox::new(basedir.join(get_tomorrow()).with_extension("md")); tomor_todo._move_in(&mut today_todo) } // INBOX -> today - pub fn collect(basedir: &Path, inbox_path: PathBuf) { + pub fn collect(inbox_path: PathBuf) { + let basedir = inbox_path.as_path().parent().unwrap(); + let mut today_todo = TaskBox::new(basedir.join(get_today()).with_extension("md")); - let mut todo = TaskBox::new(inbox_path); - today_todo._move_in(&mut todo) + let mut inbox_todo = TaskBox::new(basedir.join(INBOX_NAME).with_extension("md")); + today_todo._move_in(&mut inbox_todo) } // today -> INBOX - pub fn postp(basedir: &Path, inbox_path: PathBuf) { + pub fn postp(inbox_path: PathBuf) { + let basedir = inbox_path.as_path().parent().unwrap(); + let mut today_todo = TaskBox::new(basedir.join(get_today()).with_extension("md")); - let mut todo = TaskBox::new(inbox_path); - todo._move_in(&mut today_todo) + let mut inbox_todo = TaskBox::new(basedir.join(INBOX_NAME).with_extension("md")); + inbox_todo._move_in(&mut today_todo) } // specified markdown file -> cur @@ -264,9 +297,9 @@ impl TaskBox { let line = rline.trim(); if line.is_empty() { continue } - if line.starts_with(PREFIX) { - println!("{} : {}", " 󰄗".to_string().red(), &line[6..]); - newt.push((line[6..].to_string(), false)) + if let Some(stripped) = line.strip_prefix(PREFIX) { + println!("{} : {}", " 󰄗".to_string().red(), stripped); + newt.push((stripped.to_string(), false)) } } @@ -278,4 +311,27 @@ impl TaskBox { self._dump(); } } + + pub fn list_boxes(inbox_path: PathBuf) { + let basedir = inbox_path.as_path().parent().unwrap(); + println!("[ {} ]", basedir.display().to_string().purple()); + + let mut boxes = Vec::new(); + for entry in fs::read_dir(basedir).expect("cannot read dir") { + let path = entry.expect("cannot get entry").path(); + if path.is_file() && path.extension().unwrap() == "md" { + boxes.push(String::from(path.file_stem().unwrap().to_str().unwrap())) + } + } + boxes.sort(); boxes.reverse(); boxes.into_iter().for_each( + |b| { + print!("{} {}","󰄹".to_string().blue(), b); + let tbox = TaskBox::new(basedir.join(b).with_extension("md")); + if tbox.alias.is_some() { + println!(" ({})", tbox.alias.unwrap().bright_black().blink()) + } else { + println!() + } + }) + } } diff --git a/src/util.rs b/src/util.rs index ffc2872..343f2be 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,24 +1,8 @@ -use std::path::{Path, PathBuf}; -use std::fs; +use std::path::Path; use std::env; -use dirs; use cmd_lib::*; use colored::Colorize; -const DATA_BASE : &str = ".local/share/todor"; -const INBOX_NAME :&str = "INBOX"; - -pub fn get_inbox_file(dir: Option, inbox: Option) -> PathBuf { - let base_path = dir.map(PathBuf::from).unwrap_or_else(|| { - dirs::home_dir() - .expect("cannot get home directory") - .join(DATA_BASE) - }); - fs::create_dir_all(&base_path).expect("Failed to create base directory"); - - base_path.join(inbox.unwrap_or(INBOX_NAME.to_string())).with_extension("md") -} - pub fn glance_all(inbox_path: &Path) { let wildpat = format!("{}/*.md", inbox_path.parent().unwrap().display()); @@ -38,16 +22,3 @@ pub fn edit_box(inbox_path: &Path) { $editor $inbox_path 2>/dev/null ).expect("cannot launch cli editor(vi?)") } - -pub fn list_boxes(basedir: &Path) { - println!("[ {} ]", basedir.display().to_string().purple()); - - let mut boxes = Vec::new(); - for entry in fs::read_dir(basedir).expect("cannot read dir") { - let path = entry.expect("cannot get entry").path(); - if path.is_file() && path.extension().unwrap() == "md" { - boxes.push(String::from(path.file_stem().unwrap().to_str().unwrap())) - } - } - boxes.sort(); boxes.reverse(); boxes.into_iter().for_each(|b| println!("󰄹 {}", b)) -}