srctrait_note_cli/
run.rs

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(&notes_dir, &note, None)?;
78    run_editor(&config, &note_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(&notes_dir, &note, Some(when))?;
87    run_editor(&config, &note_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(&notes_dir, &note, None)?;
94    run_editor(&config, &note_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(&notes_dir, &note, None)?;
101    run_editor(&config, &note_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(&notes_dir, &note)?;
108    run_editor(&config, &note_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(&notes_dir, &note)?;
115    run_editor(&config, &note_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(&notes_dir, &note)?;
122    run_editor(&config, &note_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(&notes_dir)
132    };
133    
134    if let Some(note_path) = run_picker(&config, &dir)? {
135        lib::Note::from_filepath(&notes_dir, &note_path)?;
136        run_editor(&config, &note_path)
137    } else {
138        println!("Cancelled.");
139        Ok(())
140    }
141}