From 6d686e48aa21bab4d255dab6b954899103e2ce85 Mon Sep 17 00:00:00 2001 From: Joe Bellus Date: Fri, 23 Dec 2022 01:23:45 -0500 Subject: [PATCH] Initial commit --- .gitignore | 1 + Cargo.lock | 406 ++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 24 +++ src/article.rs | 83 ++++++++++ src/error.rs | 38 +++++ src/lib.rs | 25 +++ src/site.rs | 21 +++ src/template.rs | 79 ++++++++++ 8 files changed, 677 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/article.rs create mode 100644 src/error.rs create mode 100644 src/lib.rs create mode 100644 src/site.rs create mode 100644 src/template.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f97022 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..938d9ae --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,406 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "emacs" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6797a940189d353de79bec32abe717aeeecd79a08236e84404c888354e040665" +dependencies = [ + "anyhow", + "ctor", + "emacs-macros", + "emacs_module", + "once_cell", + "rustc_version", + "thiserror", +] + +[[package]] +name = "emacs-macros" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69656fdfe7c2608b87164964db848b5c3795de7302e3130cce7131552c6be161" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "emacs_module" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3067bc974045ed2c6db333bd4fc30d3bdaafa6421a9a889fa7b2826b6f7f2fa" + +[[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.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "handlebars" +version = "4.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "035ef95d03713f2c347a72547b7cd38cbc9af7cd51e6099fb62d586d4a6dee3a" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "org-static" +version = "0.1.0" +dependencies = [ + "emacs", + "handlebars", + "lazy_static", + "serde", + "serde_json", +] + +[[package]] +name = "pest" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20" +dependencies = [ + "once_cell", + "pest", + "sha1", +] + +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d296d53 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "org-static" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + + +[lib] +crate-type = ["cdylib"] + +[dependencies] + +lazy_static = "1.4" +emacs = "0.18.0" +serde = { version = "1.0.151", features = ["derive"] } +handlebars = "4.3.6" +serde_json = "1.0.91" + +[dev-dependencies] +#emacs-rs-module = { version = "0.13.0" } + + + diff --git a/src/article.rs b/src/article.rs new file mode 100644 index 0000000..a84ca90 --- /dev/null +++ b/src/article.rs @@ -0,0 +1,83 @@ +use crate::{error::Result, site::Site, template::Template}; +use serde::Serialize; +use serde_json::json; +use std::collections::{HashMap, HashSet}; + +#[derive(Serialize, Default)] +pub struct Article { + filename: String, + date: String, + author: String, + properties: HashMap, + tags: HashSet, +} + +#[derive(Serialize, Default)] +pub struct ArticleContext { + article: Article, + content: String, +} + +impl ArticleContext { + pub fn load(article: Article) -> Result { + Ok(Self { + article, + content: String::new(), + }) + } + + #[cfg(test)] + pub fn load_string(article: Article, content: &str) -> Result { + Ok(Self { + article, + content: content.to_string(), + }) + } +} + +pub fn generate_article( + site: &Site, + article: &ArticleContext, + template: &Template, +) -> Result { + let ctx = json!({ + "site": site, + "data": article, + }); + let res = template.generate(&ctx)?; + Ok(res) +} + +#[cfg(test)] +mod tests { + use crate::template::Template; + + use super::*; + + pub fn fixture_article() -> Article { + Article { + filename: "test.org".to_string(), + date: "".to_string(), + author: "Bob Bobberson".to_string(), + properties: HashMap::new(), + tags: vec!["article", "new", "cool"] + .into_iter() + .map(String::from) + .collect(), + } + } + + #[test] + fn test_generate() { + let article_ctx = + ArticleContext::load_string(fixture_article(), "ten animals i slam in a net") + .expect("couldnt build article"); + let template = + Template::new("content: {{{data.content}}}, site: {{site.title}}".to_string()); + let site = crate::site::tests::fixture_site(); + let res = + generate_article(&site, &article_ctx, &template).expect("couldnt gnenerate template"); + + assert_eq!(res, "content: ten animals i slam in a net, site: Test Site"); + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..8359cfa --- /dev/null +++ b/src/error.rs @@ -0,0 +1,38 @@ +pub type Result = std::result::Result; + +#[derive(Debug)] +pub struct Error { + message: String, +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", &self.message) + } +} + +impl std::error::Error for Error {} + +impl Error { + pub fn new(message: &str) -> Self { + Error { + message: message.to_string(), + } + } +} + +impl From for Error { + fn from(source: handlebars::TemplateError) -> Self { + Self { + message: source.to_string(), + } + } +} + +impl From for Error { + fn from(source: handlebars::RenderError) -> Self { + Self { + message: source.to_string(), + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..922f924 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,25 @@ +#![allow(non_snake_case)] + +mod article; +mod error; +mod site; +mod template; + +use emacs::{defun, Env, Result, Value}; + +emacs::plugin_is_GPL_compatible!(); + +#[emacs::module(name = "org-static")] +fn init(_: &Env) -> Result<()> { + Ok(()) +} + +#[defun] +fn say_hello(env: &Env, _name: String) -> Result> { + let fname = env + .call("buffer-file-name", []) + .unwrap() + .into_rust::() + .unwrap(); + env.message(fname) +} diff --git a/src/site.rs b/src/site.rs new file mode 100644 index 0000000..24198c0 --- /dev/null +++ b/src/site.rs @@ -0,0 +1,21 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Default)] +pub struct Site { + title: String, +} + +#[cfg(test)] +pub mod tests { + use super::*; + + #[allow(dead_code)] + pub fn fixture_site() -> Site { + Site { + title: "Test Site".to_string(), + } + } + + #[test] + fn test_name() {} +} diff --git a/src/template.rs b/src/template.rs new file mode 100644 index 0000000..ce2a8e8 --- /dev/null +++ b/src/template.rs @@ -0,0 +1,79 @@ +use handlebars::Handlebars; +use serde::Serialize; + +use crate::{error::Result, site::Site}; + +pub struct Template { + pub template_string: String, +} + +impl Template { + pub fn new(template_string: String) -> Self { + Self { template_string } + } + + pub fn generate(&self, data: &T) -> Result { + let reg = Handlebars::new(); + + let output = reg.render_template(&self.template_string, data)?; + Ok(output) + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use serde::Serialize; + + #[derive(Serialize)] + struct TestData { + name: String, + age: i32, + tags: Vec, + } + + impl Default for TestData { + fn default() -> Self { + Self { + name: "Alice Allison".to_string(), + age: 21, + tags: vec!["cats".to_string(), "dogs".to_string(), "rust".to_string()], + } + } + } + + #[test] + fn test_template() { + let tmpl = Template::new( + "Hello, my name is {{ name }}, I am {{ age }} years old and i like {{#each tags}}{{this}} {{/each}}" + .to_string(), + ); + let res = tmpl + .generate(&TestData::default()) + .expect("Error parsing template"); + assert_eq!( + res, + "Hello, my name is Alice Allison, I am 21 years old and i like cats dogs rust " + ); + } + + #[test] + fn html_inclusion() { + let data = TestData { + name: "Alice Allison".to_string(), + ..Default::default() + }; + + let tmpl = Template::new( + "Hello, my name is {{{ name }}}, I am {{ age }} years old and i like {{#each tags}}{{this}} {{/each}}" + .to_string(), + ); + + let res = tmpl.generate(&data).expect("Error parsing template"); + assert_eq!( + res, + "Hello, my name is Alice Allison, I am 21 years old and i like cats dogs rust " + ); + } +}