diff --git a/Cargo.lock b/Cargo.lock index a4a1536..5b42a12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,7 +173,7 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "day-reporter" -version = "1.0.0" +version = "1.1.0" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 4eb7199..9eaa0d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "day-reporter" -version = "1.0.0" +version = "1.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/main.rs b/src/main.rs index 0523aef..529d9d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,6 @@ use reporter::{MarkdownReporter, Reporter, Resolution, ReportOptions}; use things::task::{Task, Status}; use anyhow::Result; use clap::{Parser, ValueEnum}; -use names::sanitize_names; #[derive(ValueEnum, Copy, Clone, Eq, PartialEq)] enum Modes { @@ -22,12 +21,13 @@ enum Modes { } impl Modes { - fn format_tasks(&self, tasks: Vec, tags: &Vec) -> String { + fn format_tasks(&self, tasks: Vec, tags: &Vec, sanitize_names: bool) -> String { match self { Modes::Morning => { let task_report = MarkdownReporter.report(tasks, &ReportOptions { resolution: Resolution::FullTask, tags: tags.to_vec(), + sanitize_names, }); format!("{}\n\n{}", emoji::pick(3).join(" "), task_report) }, @@ -35,6 +35,7 @@ impl Modes { let task_report = MarkdownReporter.report(tasks, &ReportOptions { resolution: Resolution::FullTask, tags: tags.to_vec(), + sanitize_names, }); format!("Stopping now\n\n{}", task_report) }, @@ -48,6 +49,7 @@ impl Modes { let task_report = MarkdownReporter.report(further_filtered, &ReportOptions { resolution: Resolution::Project, tags: tags.to_vec(), + sanitize_names, }); format!("*Cycle Report*\n\n{}", task_report) }, @@ -72,6 +74,12 @@ struct CliArgs { #[arg(short, long, default_value_t = Modes::default())] #[clap(value_enum)] mode: Modes, + + /// By default, any @ style tags will be sanitized in the output to avoid @-mentions in + /// slack. This is done by replacing vowel characters with look unicode lookalikes. If this + /// flag is set then the names will be passed through unsanitized + #[arg(long, default_value_t = false)] + no_sanitize: bool, } fn main() -> Result<()> { @@ -84,9 +92,8 @@ fn main() -> Result<()> { let reported: Vec = tasks.into_iter().filter(|task| { args.tags.iter().all(|tag| task.has_tag(tag)) }).collect(); - let report = args.mode.format_tasks(reported, &args.tags); - let sanitized = sanitize_names(&report, &args.tags); - println!("{sanitized}"); + let report = args.mode.format_tasks(reported, &args.tags, !args.no_sanitize); + println!("{report}"); Ok(()) } diff --git a/src/reporter.rs b/src/reporter.rs index 0cc72f3..8a26526 100644 --- a/src/reporter.rs +++ b/src/reporter.rs @@ -1,4 +1,5 @@ use crate::things::task::Task; +use crate::names::sanitize_names; /// Given a notes field and a list of possible tags for sections, return the content of triple tick /// blocks containing those tags @@ -36,6 +37,7 @@ pub struct ProjectTree { id: String, title: String, notes: Option, + tags: Vec, tasks: Vec, } @@ -72,6 +74,7 @@ impl AreaTree { id: project.id.clone(), title: project.title.clone(), notes: project.notes.clone(), + tags: project.tags.clone(), tasks: vec![task], }); } @@ -103,6 +106,7 @@ impl ThingsTree { id: project.id.clone(), title: project.title.clone(), notes: project.notes.clone(), + tags: project.tags.clone(), tasks: vec![task], }); } @@ -130,6 +134,7 @@ pub enum Resolution { pub struct ReportOptions { pub resolution: Resolution, pub tags: Vec, + pub sanitize_names: bool, } pub trait Reporter { @@ -171,7 +176,11 @@ impl Reporter for MarkdownReporter { .map(|l| format!("\n{}- {}", String::from(" ").repeat(depth + 4), l)) .collect::>() .join(""); - format!("\n{}- {}{}", String::from(" ").repeat(depth), task.title, relevant_notes) + let mut output = format!("\n{}- {}{}", String::from(" ").repeat(depth), task.title, relevant_notes); + if options.sanitize_names { + output = sanitize_names(&output, &task.tags); + } + return output; } fn report_project(&mut self, project: &ProjectTree, depth: usize, options: &ReportOptions) -> String { let resolution = &options.resolution; @@ -182,7 +191,7 @@ impl Reporter for MarkdownReporter { .map(|l| format!("\n{}- {}", String::from(" ").repeat(depth + 4), l)) .collect::>() .join(""); - match resolution { + let mut output = match resolution { Resolution::FullTask => { let tasks = project.tasks .iter() @@ -194,7 +203,13 @@ impl Reporter for MarkdownReporter { Resolution::Project => { format!("{}- {}{}", String::from(" ").repeat(depth), project.title, relevant_notes) } + }; + + if options.sanitize_names { + output = sanitize_names(&output, &project.tags); } + + return output; } fn report_single_area(&mut self, area: &AreaTree, options: &ReportOptions) -> String { let project_reports = area.projects diff --git a/src/things/logbook.js b/src/things/logbook.js index 7124fcd..dd3439e 100644 --- a/src/things/logbook.js +++ b/src/things/logbook.js @@ -27,7 +27,13 @@ logbook.filter(task => { notes: todo.notes() || null, status: todo.status(), completion_date: todo.completionDate(), - project: proj && { id: proj.id(), title: proj.name(), status: proj.status(), notes: proj.notes() }, + project: proj && { + id: proj.id(), + title: proj.name(), + status: proj.status(), + notes: proj.notes(), + tags: proj.tagNames().split(', '), + }, area: area && { id: area.id(), title: area.name() }, tags: [...tags, ...todo.tagNames().split(', ')].filter(t => t), }); diff --git a/src/things/logbook_cycle.js b/src/things/logbook_cycle.js index b902324..292a7f5 100644 --- a/src/things/logbook_cycle.js +++ b/src/things/logbook_cycle.js @@ -27,7 +27,13 @@ logbook.filter(task => { notes: todo.notes() || null, status: todo.status(), completion_date: todo.completionDate(), - project: proj && { id: proj.id(), title: proj.name(), status: proj.status(), notes: proj.notes() }, + project: proj && { + id: proj.id(), + title: proj.name(), + status: proj.status(), + notes: proj.notes(), + tags: proj.tagNames().split(', '), + }, area: area && { id: area.id(), title: area.name() }, tags: [...tags, ...todo.tagNames().split(', ')].filter(t => t), }); diff --git a/src/things/task.rs b/src/things/task.rs index 3e8e15b..a8bc62d 100644 --- a/src/things/task.rs +++ b/src/things/task.rs @@ -19,6 +19,7 @@ pub enum Status { pub struct Project { pub id: String, pub title: String, + pub tags: Vec, pub notes: Option, pub status: Status, } diff --git a/src/things/today.js b/src/things/today.js index 8d57d48..6b5cf85 100644 --- a/src/things/today.js +++ b/src/things/today.js @@ -15,7 +15,13 @@ today.forEach(todo => { notes: todo.notes() || null, status: todo.status(), completion_date: todo.completionDate(), - project: proj && { id: proj.id(), title: proj.name(), status: proj.status(), notes: proj.notes() }, + project: proj && { + id: proj.id(), + title: proj.name(), + status: proj.status(), + notes: proj.notes(), + tags: proj.tagNames().split(', '), + }, area: area && { id: area.id(), title: area.name() }, tags: [...tags, ...todo.tagNames().split(', ')].filter(t => t), });