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