diff options
author | Lars Wirzenius <liw@liw.fi> | 2021-04-08 08:24:40 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2021-04-08 09:37:21 +0300 |
commit | fc917bf829c8a7cbf950754abc7085ffb00dbf17 (patch) | |
tree | debaa476835926b80af97d47d4df6c7a72c2e0c7 | |
parent | 518e7dc2d5f97387702af0a300cc2842bd0deec6 (diff) | |
download | jt2-fc917bf829c8a7cbf950754abc7085ffb00dbf17.tar.gz |
feat! add support for tera templates for new journal entries
There is a hardcoded default template, plus one can be overridden per
journal by adding a .config/templates/new_entry file in the journal.
-rw-r--r-- | Cargo.lock | 278 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | jt.md | 22 | ||||
-rw-r--r-- | src/error.rs | 8 | ||||
-rw-r--r-- | src/journal.rs | 18 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/template.rs | 45 |
7 files changed, 370 insertions, 3 deletions
@@ -48,6 +48,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "bstr" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" +dependencies = [ + "memchr", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -82,6 +124,26 @@ dependencies = [ ] [[package]] +name = "crossbeam-utils" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array", +] + +[[package]] name = "directories-next" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -122,6 +184,27 @@ dependencies = [ ] [[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] name = "getrandom" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -133,6 +216,30 @@ dependencies = [ ] [[package]] +name = "globset" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags", + "ignore", + "walkdir", +] + +[[package]] name = "heck" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -160,6 +267,30 @@ dependencies = [ ] [[package]] +name = "ignore" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c" +dependencies = [ + "crossbeam-utils", + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] name = "jt2" version = "0.1.0" dependencies = [ @@ -172,6 +303,7 @@ dependencies = [ "serde", "serde_yaml", "structopt", + "tera", "thiserror", ] @@ -203,6 +335,12 @@ dependencies = [ ] [[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] name = "memchr" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -228,6 +366,61 @@ dependencies = [ ] [[package]] +name = "once_cell" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1", +] + +[[package]] name = "pretty_env_logger" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -322,6 +515,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" [[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] name = "serde" version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -342,6 +550,17 @@ dependencies = [ ] [[package]] +name = "serde_json" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] name = "serde_yaml" version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -354,6 +573,18 @@ dependencies = [ ] [[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + +[[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -395,6 +626,21 @@ dependencies = [ ] [[package]] +name = "tera" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cb278a72e426f291faf182cb0e0cb7d20241e8e9881046724ac874a83c62346" +dependencies = [ + "globwalk", + "lazy_static", + "pest", + "pest_derive", + "regex", + "serde", + "serde_json", +] + +[[package]] name = "termcolor" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -433,6 +679,15 @@ dependencies = [ ] [[package]] +name = "thread_local" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" +dependencies = [ + "once_cell", +] + +[[package]] name = "time" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -443,6 +698,18 @@ dependencies = [ ] [[package]] +name = "typenum" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] name = "unicode-segmentation" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -473,6 +740,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -15,3 +15,4 @@ serde = { version = "1", features = ["derive"] } serde_yaml = "0.8" regex = "1" chrono = "0.4" +tera = { version = "1", default-features = false } @@ -224,6 +224,28 @@ then there are no drafts in jrnl +## Override template for new journal entries + +Verify that we can have a custom template for new journal entries. + +~~~scenario +given an installed jt + +when I run jt2 --dirname jrnl init default "My test journal" +then command is successful + +given file jrnl/.config/templates/new_entry from new_entry_template + +when I run jt2 --editor=none --dirname=jrnl new "Abracadabra" +then command is successful +and there is one draft in jrnl +and draft 0 in jrnl contains "custom new entry template" +~~~ + +~~~{#new_entry_template .file .numberLines} +This is a custom new entry template. +~~~ + # Colophon This document is meant to be processed with the [Subplot][] program to diff --git a/src/error.rs b/src/error.rs index 199d1e4..a6f239e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -61,4 +61,12 @@ pub enum JournalError { /// Editor failed. #[error("editor {0} failed: {1}")] EditorFailed(PathBuf, String), + + /// Template not found. + #[error("template not found: {0}")] + TemplateNotFound(String), + + /// Failed to render a Tera template. + #[error("template {0} failed to render: {1}")] + TemplateRender(String, #[source] tera::Error), } diff --git a/src/journal.rs b/src/journal.rs index f58e49d..e5a692e 100644 --- a/src/journal.rs +++ b/src/journal.rs @@ -1,13 +1,16 @@ use crate::error::JournalError; +use crate::template::Templates; use chrono::Local; use std::path::{Path, PathBuf}; use std::process::Command; +use tera::Context; const MAX_DRAFT_COUNT: usize = 1000; pub struct Journal { dirname: PathBuf, entries: PathBuf, + templates: Templates, } impl Journal { @@ -23,6 +26,7 @@ impl Journal { Ok(Self { dirname: path.to_path_buf(), entries: entries.to_path_buf(), + templates: Templates::new(path)?, }) } @@ -30,7 +34,12 @@ impl Journal { if Self::is_journal(path, entries) { let dirname = path.to_path_buf(); let entries = entries.to_path_buf(); - Ok(Self { dirname, entries }) + let templates = Templates::new(path)?; + Ok(Self { + dirname, + entries, + templates, + }) } else { Err(JournalError::NotAJournal(path.display().to_string())) } @@ -55,9 +64,12 @@ impl Journal { .map_err(|err| JournalError::CreateDirectory(drafts.to_path_buf(), err))?; } + let mut context = Context::new(); + context.insert("title", title); + let pathname = self.pick_file_id(&drafts)?; - let text = format!(r#"[[!meta title="{}"]]"#, title); - std::fs::write(&pathname, format!("{}\n\n", text)) + let text = self.templates.new_draft(&context)?; + std::fs::write(&pathname, text) .map_err(|err| JournalError::WriteEntry(pathname.to_path_buf(), err))?; self.edit(editor, &pathname)?; Ok(()) @@ -2,3 +2,4 @@ pub mod config; pub mod error; pub mod journal; pub mod opt; +pub mod template; diff --git a/src/template.rs b/src/template.rs new file mode 100644 index 0000000..1ad8a54 --- /dev/null +++ b/src/template.rs @@ -0,0 +1,45 @@ +use crate::error::JournalError; +use std::path::Path; +use tera::{Context, Tera}; + +const NEW_ENTRY: &str = r#"[[!meta title="{{ title }}"]] + +This is the default template. +"#; + +pub struct Templates { + tera: Tera, +} + +impl Templates { + pub fn new(dirname: &Path) -> Result<Self, JournalError> { + let glob = format!("{}/.config/templates/*", dirname.display()); + let mut tera = Tera::new(&glob).expect("Tera::new"); + add_default_template(&mut tera, "new_entry", NEW_ENTRY); + Ok(Self { tera }) + } + + pub fn new_draft(&self, context: &Context) -> Result<String, JournalError> { + self.render("new_entry", &context) + } + + fn render(&self, name: &str, context: &Context) -> Result<String, JournalError> { + match self.tera.render(name, &context) { + Ok(s) => Ok(s), + Err(e) => match e.kind { + tera::ErrorKind::TemplateNotFound(x) => Err(JournalError::TemplateNotFound(x)), + _ => Err(JournalError::TemplateRender(name.to_string(), e)), + }, + } + } +} + +fn add_default_template(tera: &mut Tera, name: &str, template: &str) { + let context = Context::new(); + if let Err(err) = tera.render(name, &context) { + if let tera::ErrorKind::TemplateNotFound(_) = err.kind { + tera.add_raw_template(name, template) + .expect("Tera::add_raw_template"); + } + } +} |