srctrait_note_cli/
run.rs

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(&notes_dir, &note, None)?;
77    run_editor(&config, &note_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(&notes_dir, &note, Some(when))?;
86    run_editor(&config, &note_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(&notes_dir, &note, None)?;
93    run_editor(&config, &note_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(&notes_dir, &note, None)?;
100    run_editor(&config, &note_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(&notes_dir, &note)?;
107    run_editor(&config, &note_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(&notes_dir, &note)?;
114    run_editor(&config, &note_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(&notes_dir, &note)?;
121    run_editor(&config, &note_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(&notes_dir)
131    };
132    
133    if let Some(note_path) = run_picker(&config, &dir)? {
134        lib::Note::from_filepath(&notes_dir, &note_path)?;
135        run_editor(&config, &note_path)
136    } else {
137        println!("Cancelled.");
138        Ok(())
139    }
140}