summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: c5117c8c92c5aaddabfd24b70465a28c40a021af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use anyhow::Result;
use log::debug;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use structopt::StructOpt;
use thiserror::Error;

#[derive(Debug, StructOpt)]
#[structopt(about = "maintain a journal")]
enum JT {
    Init {
        #[structopt(help = "Directory where journal should be stored")]
        dirname: PathBuf,
        #[structopt(help = "Short name for journal")]
        journalname: String,
        #[structopt(help = "Short description of journal, its title")]
        description: String,
    },
    IsJournal {
        #[structopt(help = "Directory that may or may not be a journal")]
        dirname: PathBuf,
    },
    New {
        #[structopt(long, short, help = "Use DIRNAME as the location of the journal")]
        dirname: PathBuf,
        #[structopt(
            long,
            short,
            help = "Invoke EDITOR for user to edit draft",
            default_value = "/usr/bin/editor"
        )]
        editor: String,
        #[structopt(help = "Title of new draft")]
        title: String,
    },
    Edit {
        #[structopt(long, short, help = "Use DIRNAME as the location of the journal")]
        dirname: PathBuf,
        #[structopt(
            long,
            short,
            help = "Invoke EDITOR for user to edit draft",
            default_value = "/usr/bin/editor"
        )]
        editor: String,
    },
    Finish {
        #[structopt(long, short, help = "Use DIRNAME as the location of the journal")]
        dirname: PathBuf,
    },
}

#[derive(Debug, Error)]
enum JournalError {
    #[error("directory {0} is not a journal")]
    NotAJournal(String),
}

fn main() -> Result<()> {
    pretty_env_logger::init_custom_env("JT_LOG");
    let opt = JT::from_args();
    match opt {
        JT::Init {
            dirname,
            journalname,
            description,
        } => init(&dirname, &journalname, &description)?,
        JT::IsJournal { dirname } => is_journal(&dirname)?,
        JT::New {
            title,
            dirname,
            editor,
        } => new_draft(&title, &dirname, &editor)?,
        JT::Edit { dirname, editor } => edit_draft(&dirname, &editor)?,
        JT::Finish { dirname } => finish_draft(&dirname)?,
    }
    Ok(())
}

fn init(dirname: &Path, _journalname: &str, _description: &str) -> anyhow::Result<()> {
    std::fs::create_dir(dirname)?;
    Ok(())
}

fn is_journal(dirname: &Path) -> anyhow::Result<()> {
    let meta = fs::symlink_metadata(dirname)?;
    if !meta.is_dir() {
        return Err(JournalError::NotAJournal(dirname.display().to_string()).into());
    }
    Ok(())
}

fn new_draft(title: &str, dirname: &Path, editor: &str) -> anyhow::Result<()> {
    let drafts = dirname.join("drafts");
    if !drafts.exists() {
        std::fs::create_dir(&drafts)?;
    }
    let draft_filename = drafts.join("0.md");
    std::fs::write(draft_filename, title)?;
    Ok(())
}

fn edit_draft(dirname: &Path, editor: &str) -> anyhow::Result<()> {
    debug!("edit_draft: dirname={:?}", dirname);
    debug!("edit_draft: editor={:?}", editor);
    let drafts = dirname.join("drafts");
    let draft_filename = drafts.join("0.md");
    debug!("edit_draft: draft_filename={:?}", draft_filename);
    let status = Command::new(editor).arg(draft_filename).status()?;
    debug!("edit_draft: editor finished");
    Ok(())
}

fn finish_draft(dirname: &Path) -> anyhow::Result<()> {
    let drafts = dirname.join("drafts");
    let draft = drafts.join("0.md");

    let entries = dirname.join("entries");
    if !entries.exists() {
        std::fs::create_dir(&entries)?;
    }
    let entry = entries.join("0.md");

    std::fs::rename(draft, entry)?;
    Ok(())
}