1use std::{borrow::Cow, fs, path::Path, 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),
31 Command::Pick{kind} => run_pick(kind),
32 }
33}
34
35fn init_user() -> anyhow::Result<(lib::NoteConfig, lib::NotesDir)> {
36 let config = user_notes_config()?;
37 let dir = user_notes_dir(&config)?;
38 dir.init()?;
39 Ok((config, dir))
40}
41
42fn run_config() -> anyhow::Result<()> {
43 let (config, _notes_dir) = init_user()?;
44 let config_file = note_config_file()?;
45 let first_run = !config_file.is_file();
46
47 if first_run {
48 let content = config.to_toml()?
49 .lines()
50 .map(|l| format!("#{l}"))
51 .collect::<Vec<_>>()
52 .join("\n");
53
54 fs::write(&config_file, content)?;
55 }
56
57 run_editor(&config, &config_file)?;
58
59 if first_run {
60 let content = fs::read_to_string(&config_file)
61 .with_context(|| format!("Unable to read config file: {}", config_file.display()))?
62 .lines()
63 .filter(|l| !l.starts_with('#'))
64 .collect::<Vec<_>>()
65 .join("\n");
66
67 fs::write(config_file, content)?;
68 }
69
70 Ok(())
71}
72
73fn run_today() -> anyhow::Result<()> {
74 let (config, notes_dir) = init_user()?;
75 let note = lib::Note::new(lib::NoteType::Today(lib::Date::now()));
76 let note_file = lib::note_for_date(¬es_dir, ¬e, None)?;
77 run_editor(&config, ¬e_file)
78}
79
80fn run_today_from(when: &str) -> anyhow::Result<()> {
81 let (config, notes_dir) = init_user()?;
82 let today = lib::Date::now();
83 let when = today.from(when)?;
84 let note = lib::Note::new(lib::NoteType::Today(today));
85 let note_file = lib::note_for_date(¬es_dir, ¬e, Some(when))?;
86 run_editor(&config, ¬e_file)
87}
88
89fn run_day(when: String) -> anyhow::Result<()> {
90 let (config, notes_dir) = init_user()?;
91 let note = lib::Note::new(lib::NoteType::Today(lib::Date::now().from(&when)?));
92 let note_file = lib::note_for_date(¬es_dir, ¬e, None)?;
93 run_editor(&config, ¬e_file)
94}
95
96fn run_yesterday() -> anyhow::Result<()> {
97 let (config, notes_dir) = init_user()?;
98 let note = lib::Note::new(lib::NoteType::Today(lib::Date::now().from("yesterday")?));
99 let note_file = lib::note_for_date(¬es_dir, ¬e, None)?;
100 run_editor(&config, ¬e_file)
101}
102
103fn run_idea(topic: String) -> anyhow::Result<()> {
104 let (config, notes_dir) = init_user()?;
105 let note = lib::Note::new(lib::NoteType::Idea(topic.to_string()));
106 let note_file = lib::note_for_topic(¬es_dir, ¬e)?;
107 run_editor(&config, ¬e_file)
108}
109
110fn run_todo(topic: String) -> anyhow::Result<()> {
111 let (config, notes_dir) = init_user()?;
112 let note = lib::Note::new(lib::NoteType::Todo(topic.to_string()));
113 let note_file = lib::note_for_topic(¬es_dir, ¬e)?;
114 run_editor(&config, ¬e_file)
115}
116
117fn run_plan(topic: Option<String>) -> anyhow::Result<()> {
118 let (config, notes_dir) = init_user()?;
119 let note = lib::Note::new(lib::NoteType::Plan(topic));
120 let note_file = lib::note_for_optional_topic(¬es_dir, ¬e)?;
121 run_editor(&config, ¬e_file)
122}
123
124fn run_pick(kind: Option<CliNoteKind>) -> anyhow::Result<()> {
125 let (config, notes_dir) = init_user()?;
126 let kind: Option<lib::NoteKind> = kind.map(|k| k.into());
127 let dir: Cow<'_, Path> = if let Some(kind) = kind {
128 Cow::Owned(notes_dir.kind_dir(kind))
129 } else {
130 Cow::Borrowed(¬es_dir)
131 };
132
133 if let Some(note_path) = run_picker(&config, &dir)? {
134 lib::Note::from_filepath(¬es_dir, ¬e_path)?;
135 run_editor(&config, ¬e_path)
136 } else {
137 println!("Cancelled.");
138 Ok(())
139 }
140}