From 39a6b45790c148c44e4940c89eca5bce95d99a92 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 3 Apr 2021 09:49:48 +0300 Subject: fix: read config.yaml in default config dir, not the dir itself --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 5041492..3acfd90 100644 --- a/src/config.rs +++ b/src/config.rs @@ -66,7 +66,7 @@ impl Configuration { } path.to_path_buf() } - None => proj_dirs.config_dir().to_path_buf(), + None => proj_dirs.config_dir().to_path_buf().join("config.yaml"), }; let input = if filename.exists() { InputConfiguration::read(&filename)? -- cgit v1.2.1 From 6e60becfb6fd87b1101b97006910396132be7777 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 3 Apr 2021 10:37:45 +0300 Subject: feat: launch editor for new draft --- src/error.rs | 8 ++++++++ src/journal.rs | 28 +++++++++++++++++++++------- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/error.rs b/src/error.rs index 232eaec..05bb74d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -45,4 +45,12 @@ pub enum JournalError { /// Failed to get metadata for specific file in drafts folder. #[error("failed to stat draft in {0}: {1}")] StatDraft(PathBuf, #[source] std::io::Error), + + /// Error spawning editor. + #[error("failed to start editor {0}: {1}")] + SpawnEditor(PathBuf, #[source] std::io::Error), + + /// Editor failed. + #[error("editor {0} failed: {1}")] + EditorFailed(PathBuf, String), } diff --git a/src/journal.rs b/src/journal.rs index 911f9a3..2adb48d 100644 --- a/src/journal.rs +++ b/src/journal.rs @@ -1,6 +1,5 @@ use crate::error::JournalError; use chrono::Local; -use log::debug; use std::path::{Path, PathBuf}; use std::process::Command; @@ -48,7 +47,7 @@ impl Journal { self.dirname().join("entries") } - pub fn new_draft(&self, title: &str, _editor: &str) -> anyhow::Result<()> { + pub fn new_draft(&self, title: &str, editor: &str) -> anyhow::Result<()> { let drafts = self.drafts(); if !drafts.exists() { std::fs::create_dir(&drafts)?; @@ -56,7 +55,8 @@ impl Journal { let pathname = self.pick_file_id(&drafts)?; let text = format!(r#"[[!meta title="{}"]]"#, title); - std::fs::write(pathname, format!("{}\n\n", text))?; + std::fs::write(&pathname, format!("{}\n\n", text))?; + self.edit(editor, &pathname)?; Ok(()) } @@ -84,11 +84,25 @@ impl Journal { } } + fn edit(&self, editor: &str, filename: &Path) -> Result<(), JournalError> { + match Command::new(editor).arg(filename).output() { + Err(err) => Err(JournalError::SpawnEditor(filename.to_path_buf(), err)), + Ok(output) => { + if output.status.success() { + Ok(()) + } else { + let stderr = String::from_utf8_lossy(&output.stderr); + Err(JournalError::EditorFailed( + filename.to_path_buf(), + stderr.into_owned(), + )) + } + } + } + } + pub fn edit_draft(&self, editor: &str, filename: &Path) -> anyhow::Result<()> { - debug!("edit_draft: editor={:?}", editor); - debug!("edit_draft: filename={:?}", filename); - Command::new(editor).arg(filename).status()?; - debug!("edit_draft: editor finished"); + self.edit(editor, filename)?; Ok(()) } -- cgit v1.2.1 From ced4b9e5ff28016f500c5bfea91a3b33297f65d1 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Sat, 3 Apr 2021 11:04:40 +0300 Subject: feat: allow setting name of directory where new entries go Also, some refactoring that happened along the way. --- jt.md | 1 + src/bin/jt2.rs | 41 +++++++++++++++++++++++------------------ src/config.rs | 29 ++++++++++++++++++++++------- src/journal.rs | 39 ++++++++++++++++++++++++++------------- src/opt.rs | 4 ++++ subplot/jt.py | 6 ++++++ subplot/jt.yaml | 3 +++ 7 files changed, 85 insertions(+), 38 deletions(-) diff --git a/jt.md b/jt.md index ad40b35..9ee4d1d 100644 --- a/jt.md +++ b/jt.md @@ -164,6 +164,7 @@ and draft 0 in jrnl contains "Open sesame!" when I run jt2 --dirname=jrnl finish 0 abra then command is successful and there is one journal entry in jrnl, at FILE +and file name ends with .mdwn and journal entry contains "Abracadabra" and journal entry contains "Open sesame!" and there are no drafts in jrnl diff --git a/src/bin/jt2.rs b/src/bin/jt2.rs index 3d85229..25a3a13 100644 --- a/src/bin/jt2.rs +++ b/src/bin/jt2.rs @@ -15,42 +15,47 @@ fn main() -> anyhow::Result<()> { SubCommand::Init { journalname, description, - } => init(&config.dirname, &journalname, &description)?, - SubCommand::IsJournal => is_journal(&config.dirname)?, - SubCommand::New { title } => new_draft(&title, &config.dirname, &config.editor)?, - SubCommand::Edit { draft } => edit_draft(&config.dirname, &config.editor, &draft)?, - SubCommand::Finish { draft, basename } => finish_draft(&config.dirname, &draft, &basename)?, + } => init(&config.dirname, &journalname, &description, &config)?, + SubCommand::IsJournal => is_journal(&config)?, + SubCommand::New { title } => new_draft(&title, &config)?, + SubCommand::Edit { draft } => edit_draft(&draft, &config)?, + SubCommand::Finish { draft, basename } => finish_draft(&draft, &basename, &config)?, } Ok(()) } -fn init(dirname: &Path, _journalname: &str, _description: &str) -> anyhow::Result<()> { - Journal::init(dirname)?; +fn init( + dirname: &Path, + _journalname: &str, + _description: &str, + config: &Configuration, +) -> anyhow::Result<()> { + Journal::init(dirname, &config.entries)?; Ok(()) } -fn is_journal(dirname: &Path) -> anyhow::Result<()> { - if !Journal::is_journal(dirname) { - return Err(JournalError::NotAJournal(dirname.display().to_string()).into()); +fn is_journal(config: &Configuration) -> anyhow::Result<()> { + if !Journal::is_journal(&config.dirname, &config.entries) { + return Err(JournalError::NotAJournal(config.dirname.display().to_string()).into()); } Ok(()) } -fn new_draft(title: &str, dirname: &Path, editor: &str) -> anyhow::Result<()> { - let journal = Journal::new(dirname)?; - journal.new_draft(title, editor)?; +fn new_draft(title: &str, config: &Configuration) -> anyhow::Result<()> { + let journal = Journal::new(&config.dirname, &config.entries)?; + journal.new_draft(title, &config.editor)?; Ok(()) } -fn edit_draft(dirname: &Path, editor: &str, draft: &str) -> anyhow::Result<()> { - let journal = Journal::new(dirname)?; +fn edit_draft(draft: &str, config: &Configuration) -> anyhow::Result<()> { + let journal = Journal::new(&config.dirname, &config.entries)?; let filename = journal.pick_draft(draft)?; - journal.edit_draft(editor, &filename)?; + journal.edit_draft(&config.editor, &filename)?; Ok(()) } -fn finish_draft(dirname: &Path, draft: &str, basename: &str) -> anyhow::Result<()> { - let journal = Journal::new(dirname)?; +fn finish_draft(draft: &str, basename: &str, config: &Configuration) -> anyhow::Result<()> { + let journal = Journal::new(&config.dirname, &config.entries)?; let filename = journal.pick_draft(draft)?; journal.finish_draft(&filename, basename)?; Ok(()) diff --git a/src/config.rs b/src/config.rs index 3acfd90..e40c35f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -19,6 +19,7 @@ const APP: &str = "jt2"; struct InputConfiguration { dirname: Option, editor: Option, + entries: Option, } impl InputConfiguration { @@ -43,6 +44,11 @@ pub struct Configuration { /// The editor to open for editing journal entry drafts. pub editor: String, + + /// The directory where new entries are put. + /// + /// This is the full path name, not relative to `dirname`. + pub entries: PathBuf, } impl Configuration { @@ -74,14 +80,16 @@ impl Configuration { InputConfiguration::default() }; + let dirname = if let Some(path) = &opt.global.dirname { + path.to_path_buf() + } else if let Some(path) = &input.dirname { + expand_tilde(path) + } else { + proj_dirs.data_dir().to_path_buf() + }; + Ok(Self { - dirname: if let Some(path) = &opt.global.dirname { - path.to_path_buf() - } else if let Some(path) = &input.dirname { - expand_tilde(path) - } else { - proj_dirs.data_dir().to_path_buf() - }, + dirname: dirname.clone(), editor: if let Some(name) = &opt.global.editor { name.to_string() } else if let Some(name) = &input.editor { @@ -89,6 +97,13 @@ impl Configuration { } else { "/usr/bin/editor".to_string() }, + entries: if let Some(entries) = &opt.global.entries { + dirname.join(entries) + } else if let Some(entries) = &input.entries { + dirname.join(entries) + } else { + dirname.join("entries") + }, }) } diff --git a/src/journal.rs b/src/journal.rs index 2adb48d..c3bb1eb 100644 --- a/src/journal.rs +++ b/src/journal.rs @@ -7,31 +7,32 @@ const MAX_DRAFT_COUNT: usize = 1000; pub struct Journal { dirname: PathBuf, + entries: PathBuf, } impl Journal { - pub fn is_journal(path: &Path) -> bool { - if let Ok(meta) = std::fs::symlink_metadata(path) { - meta.is_dir() - } else { - false - } + pub fn is_journal(path: &Path, entries: &Path) -> bool { + is_dir(path) && is_dir(entries) } - pub fn init(path: &Path) -> Result { + pub fn init(path: &Path, entries: &Path) -> Result { std::fs::create_dir(path) .map_err(|err| JournalError::CreateDirectory(path.to_path_buf(), err))?; + std::fs::create_dir(entries) + .map_err(|err| JournalError::CreateDirectory(entries.to_path_buf(), err))?; Ok(Self { dirname: path.to_path_buf(), + entries: entries.to_path_buf(), }) } - pub fn new(path: &Path) -> Result { - let dirname = path.to_path_buf(); - if dirname.exists() { - Ok(Self { dirname }) + pub fn new(path: &Path, entries: &Path) -> Result { + if Self::is_journal(path, entries) { + let dirname = path.to_path_buf(); + let entries = entries.to_path_buf(); + Ok(Self { dirname, entries }) } else { - Err(JournalError::NotAJournal(dirname.display().to_string())) + Err(JournalError::NotAJournal(path.display().to_string())) } } @@ -44,7 +45,7 @@ impl Journal { } fn entries(&self) -> PathBuf { - self.dirname().join("entries") + self.entries.clone() } pub fn new_draft(&self, title: &str, editor: &str) -> anyhow::Result<()> { @@ -85,6 +86,9 @@ impl Journal { } fn edit(&self, editor: &str, filename: &Path) -> Result<(), JournalError> { + if editor == "none" { + return Ok(()); + } match Command::new(editor).arg(filename).output() { Err(err) => Err(JournalError::SpawnEditor(filename.to_path_buf(), err)), Ok(output) => { @@ -115,8 +119,17 @@ impl Journal { let subdir = entries.join(Local::today().format("%Y/%m/%d").to_string()); std::fs::create_dir_all(&subdir)?; + let basename = PathBuf::from(format!("{}.mdwn", basename)); let entry = subdir.join(basename); std::fs::rename(filename, entry)?; Ok(()) } } + +fn is_dir(path: &Path) -> bool { + if let Ok(meta) = std::fs::symlink_metadata(path) { + meta.is_dir() + } else { + false + } +} diff --git a/src/opt.rs b/src/opt.rs index df83659..5455777 100644 --- a/src/opt.rs +++ b/src/opt.rs @@ -29,6 +29,10 @@ pub struct GlobalOptions { #[structopt(short, long, help = "Directory where journal should be stored")] pub dirname: Option, + /// Sub-directory in journal where new entries are put. + #[structopt(long)] + pub entries: Option, + /// Which editor to invoke for editing journal entry drafts. #[structopt( long, diff --git a/subplot/jt.py b/subplot/jt.py index 312a22a..6ce75b0 100644 --- a/subplot/jt.py +++ b/subplot/jt.py @@ -153,3 +153,9 @@ def file_contains(ctx, variable=None, pattern=None): data = f.read() logging.debug(f"file content: {data!r}") assert pattern in data + + +def file_name_has_suffix(ctx, varname=None, suffix=None): + variables = ctx.get("variables", {}) + filename = variables[varname] + assert filename.endswith(suffix) diff --git a/subplot/jt.yaml b/subplot/jt.yaml index 187f436..65bf90e 100644 --- a/subplot/jt.yaml +++ b/subplot/jt.yaml @@ -54,3 +54,6 @@ - then: journal entry <{variable}> contains "{pattern:text}" function: file_contains + +- then: file name <{varname}> ends with {suffix} + function: file_name_has_suffix -- cgit v1.2.1