1use std::{fs, process::ExitCode};
2use clap::Parser;
3use crate::*;
4
5pub fn run() -> ExitCode {
6 match run_cli() {
7 Ok(_) => ExitCode::SUCCESS,
8 Err(e) => {
9 let source = e.source()
10 .map_or(String::new(), |s| format!("\n {s}"));
11
12 eprintln!("{ERROR}error:{ERROR:#} {e}{source}");
13 ExitCode::FAILURE
14 }
15 }
16}
17
18fn run_cli() -> anyhow::Result<()> {
19 let cli = Cli::parse();
20 match &cli.command {
21 Command::Config => run_config(),
22 Command::Today(cmd) => match &cmd.from {
23 Some(TodaySubCommand::From{when}) => run_today_from(when),
24 None => run_today()
25 },
26 Command::Yesterday => run_yesterday(),
27 Command::Day{when} => run_day(when),
28 Command::Idea{topic} => run_idea(topic),
29 Command::Todo{topic} => run_todo(topic),
30 Command::Plan{topic} => run_plan(topic.as_deref()),
31 }
32}
33
34fn init_user() -> anyhow::Result<(lib::NoteConfig, lib::NotesDir)> {
35 let config = user_notes_config()?;
36 let dir = user_notes_dir(&config)?;
37 dir.init()?;
38 Ok((config, dir))
39}
40
41fn run_config() -> anyhow::Result<()> {
42 let (config, _notes_dir) = init_user()?;
43 let config_file = note_config_file()?;
44 let first_run = !config_file.is_file();
45
46 if first_run {
47 let content = config.to_toml()?
48 .lines()
49 .map(|l| format!("#{l}"))
50 .collect::<Vec<_>>()
51 .join("\n");
52
53 fs::write(&config_file, content)?;
54 }
55
56 run_editor(&config, &config_file)?;
57
58 if first_run {
59 let content = fs::read_to_string(&config_file)
60 .with_context(|| format!("Unable to read config file: {}", config_file.display()))?
61 .lines()
62 .filter(|l| !l.starts_with('#'))
63 .collect::<Vec<_>>()
64 .join("\n");
65
66 fs::write(config_file, content)?;
67 }
68
69 Ok(())
70}
71
72fn run_today() -> anyhow::Result<()> {
73 let (config, notes_dir) = init_user()?;
74 let today = lib::Date::now();
75 let note_file = lib::note_for_date(notes_dir, today, None)?;
76 run_editor(&config, ¬e_file)
77}
78
79fn run_today_from(when: &str) -> anyhow::Result<()> {
80 let (config, notes_dir) = init_user()?;
81 let today = lib::Date::now();
82 let when = today.from(when)?;
83 let note_file = lib::note_for_date(notes_dir, today, Some(when))?;
84 run_editor(&config, ¬e_file)
85}
86
87fn run_day(when: &str) -> anyhow::Result<()> {
88 let (config, notes_dir) = init_user()?;
89 let day = lib::Date::now().from(&when)?;
90 let note_file = lib::note_for_date(notes_dir, day, None)?;
91 run_editor(&config, ¬e_file)
92}
93
94fn run_yesterday() -> anyhow::Result<()> {
95 let (config, notes_dir) = init_user()?;
96 let day = lib::Date::now().from("yesterday")?;
97 let note_file = lib::note_for_date(notes_dir, day, None)?;
98 run_editor(&config, ¬e_file)
99}
100
101fn run_idea(topic: &str) -> anyhow::Result<()> {
102 let (config, notes_dir) = init_user()?;
103 let note_file = lib::note_for_topic(notes_dir, lib::NoteKind::Idea, topic)?;
104 run_editor(&config, ¬e_file)
105}
106
107fn run_todo(topic: &str) -> anyhow::Result<()> {
108 let (config, notes_dir) = init_user()?;
109 let note_file = lib::note_for_topic(notes_dir, lib::NoteKind::Todo, topic)?;
110 run_editor(&config, ¬e_file)
111}
112
113fn run_plan(topic: Option<&str>) -> anyhow::Result<()> {
114 let (config, notes_dir) = init_user()?;
115 let kind = match topic {
116 Some(_) => lib::NoteKind::PlanTopic,
117 None => lib::NoteKind::Plan,
118 };
119
120 let note_file = lib::note_for_optional_topic(notes_dir, kind, topic)?;
121 run_editor(&config, ¬e_file)
122}