diff options
| author | Christine Dodrill <me@christine.website> | 2020-09-19 11:33:46 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-09-19 11:33:46 -0400 |
| commit | a2fba89738caac83ce24d40b762d6205f2266361 (patch) | |
| tree | 3a61afb3b1a9d42b0a61b67be527322b6740f179 /src | |
| parent | 1e61d2ad33f7ac7751063bdd373ab3d1305015e2 (diff) | |
| download | xesite-a2fba89738caac83ce24d40b762d6205f2266361.tar.xz xesite-a2fba89738caac83ce24d40b762d6205f2266361.zip | |
TL;DR Rust (#210)
* start mara code
* better alt text
* more mara tests
* cleanups
* blog: start tl;dr rust post
* more words
* feature complete
* little oopses
* oops lol
Diffstat (limited to 'src')
| -rw-r--r-- | src/app/markdown.rs | 79 | ||||
| -rw-r--r-- | src/app/mod.rs (renamed from src/app.rs) | 24 | ||||
| -rw-r--r-- | src/main.rs | 3 | ||||
| -rw-r--r-- | src/post/frontmatter.rs | 2 | ||||
| -rw-r--r-- | src/post/mod.rs | 15 | ||||
| -rw-r--r-- | src/signalboost.rs | 2 |
6 files changed, 97 insertions, 28 deletions
diff --git a/src/app/markdown.rs b/src/app/markdown.rs new file mode 100644 index 0000000..fe33a21 --- /dev/null +++ b/src/app/markdown.rs @@ -0,0 +1,79 @@ +use color_eyre::eyre::{Result, WrapErr}; +use comrak::nodes::{Ast, AstNode, NodeValue}; +use comrak::{format_html, parse_document, markdown_to_html, Arena, ComrakOptions}; +use std::cell::RefCell; +use crate::templates::Html; +use url::Url; + +pub fn render(inp: &str) -> Result<String> { + let mut options = ComrakOptions::default(); + + options.extension.autolink = true; + options.extension.table = true; + options.extension.description_lists = true; + options.extension.superscript = true; + options.extension.strikethrough = true; + options.extension.footnotes = true; + + options.render.unsafe_ = true; + + let arena = Arena::new(); + let root = parse_document(&arena, inp, &options); + + iter_nodes(root, &|node| { + let mut data = node.data.borrow_mut(); + match &mut data.value { + &mut NodeValue::Link(ref mut link) => { + let base = Url::parse("https://christine.website/")?; + let u = base.join(std::str::from_utf8(&link.url.clone())?)?; + if u.scheme() != "conversation" { + return Ok(()); + } + let parent = node.parent().unwrap(); + node.detach(); + let mut message = vec![]; + for child in node.children() { + format_html(child, &options, &mut message)?; + } + let message = std::str::from_utf8(&message)?; + let message = markdown_to_html(message, &options); + let mood = without_first(u.path()); + let name = u.host_str().unwrap_or("Mara"); + + let mut html = vec![]; + crate::templates::mara(&mut html, mood, name, Html(message))?; + + let new_node = + arena.alloc(AstNode::new(RefCell::new(Ast::new(NodeValue::HtmlInline(html))))); + parent.append(new_node); + + Ok(()) + } + _ => Ok(()), + } + })?; + + let mut html = vec![]; + format_html(root, &options, &mut html).unwrap(); + + String::from_utf8(html).wrap_err("post is somehow invalid UTF-8") +} + +fn iter_nodes<'a, F>(node: &'a AstNode<'a>, f: &F) -> Result<()> +where + F: Fn(&'a AstNode<'a>) -> Result<()>, +{ + f(node)?; + for c in node.children() { + iter_nodes(c, f)?; + } + Ok(()) +} + +fn without_first(string: &str) -> &str { + string + .char_indices() + .nth(1) + .and_then(|(i, _)| string.get(i..)) + .unwrap_or("") +} diff --git a/src/app.rs b/src/app/mod.rs index 5ffca7c..44f05e7 100644 --- a/src/app.rs +++ b/src/app/mod.rs @@ -1,9 +1,10 @@ use crate::{post::Post, signalboost::Person}; -use anyhow::Result; -use comrak::{markdown_to_html, ComrakOptions}; +use color_eyre::eyre::Result; use serde::Deserialize; use std::{fs, path::PathBuf}; +pub mod markdown; + #[derive(Clone, Deserialize)] pub struct Config { #[serde(rename = "clackSet")] @@ -14,21 +15,6 @@ pub struct Config { resume_fname: PathBuf, } -pub fn markdown(inp: &str) -> String { - let mut options = ComrakOptions::default(); - - options.extension.autolink = true; - options.extension.table = true; - options.extension.description_lists = true; - options.extension.superscript = true; - options.extension.strikethrough = true; - options.extension.footnotes = true; - - options.render.unsafe_ = true; - - markdown_to_html(inp, &options) -} - async fn patrons() -> Result<Option<patreon::Users>> { use patreon::*; let creds: Credentials = envy::prefixed("PATREON_").from_env().unwrap(); @@ -72,7 +58,7 @@ pub async fn init(cfg: PathBuf) -> Result<State> { let cfg: Config = serde_dhall::from_file(cfg).parse()?; let sb = cfg.signalboost.clone(); let resume = fs::read_to_string(cfg.resume_fname.clone())?; - let resume: String = markdown(&resume); + let resume: String = markdown::render(&resume)?; let blog = crate::post::load("blog")?; let gallery = crate::post::load("gallery")?; let talks = crate::post::load("talks")?; @@ -145,7 +131,7 @@ pub async fn init(cfg: PathBuf) -> Result<State> { #[cfg(test)] mod tests { - use anyhow::Result; + use color_eyre::eyre::Result; #[tokio::test] async fn init() -> Result<()> { let _ = pretty_env_logger::try_init(); diff --git a/src/main.rs b/src/main.rs index aa5400e..c1e9e1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use color_eyre::eyre::Result; use hyper::{header::CONTENT_TYPE, Body, Response}; use prometheus::{Encoder, TextEncoder}; use std::sync::Arc; @@ -21,6 +21,7 @@ fn with_state( #[tokio::main] async fn main() -> Result<()> { + color_eyre::install()?; let _ = kankyo::init(); pretty_env_logger::init(); log::info!("starting up commit {}", env!("GITHUB_SHA")); diff --git a/src/post/frontmatter.rs b/src/post/frontmatter.rs index 1cc8032..615f2c5 100644 --- a/src/post/frontmatter.rs +++ b/src/post/frontmatter.rs @@ -1,6 +1,6 @@ /// This code was borrowed from @fasterthanlime. -use anyhow::{Result}; +use color_eyre::eyre::{Result}; use serde::{Serialize, Deserialize}; #[derive(Eq, PartialEq, Deserialize, Default, Debug, Serialize, Clone)] diff --git a/src/post/mod.rs b/src/post/mod.rs index a948017..c0062a4 100644 --- a/src/post/mod.rs +++ b/src/post/mod.rs @@ -1,5 +1,5 @@ -use anyhow::{anyhow, Result}; use chrono::prelude::*; +use color_eyre::eyre::{eyre, Result, WrapErr}; use glob::glob; use std::{cmp::Ordering, fs}; @@ -75,8 +75,10 @@ pub fn load(dir: &str) -> Result<Vec<Post>> { for path in glob(&format!("{}/*.markdown", dir))?.filter_map(Result::ok) { log::debug!("loading {:?}", path); - let body = fs::read_to_string(path.clone()).expect("things to work"); - let (fm, content_offset) = frontmatter::Data::parse(body.clone().as_str()).expect("stuff to work"); + let body = + fs::read_to_string(path.clone()).wrap_err_with(|| format!("can't read {:?}", path))?; + let (fm, content_offset) = frontmatter::Data::parse(body.clone().as_str()) + .wrap_err_with(|| format!("can't parse frontmatter of {:?}", path))?; let markup = &body[content_offset..]; let date = NaiveDate::parse_from_str(&fm.clone().date, "%Y-%m-%d")?; @@ -84,7 +86,8 @@ pub fn load(dir: &str) -> Result<Vec<Post>> { front_matter: fm, link: format!("{}/{}", dir, path.file_stem().unwrap().to_str().unwrap()), body: markup.to_string(), - body_html: crate::app::markdown(&markup), + body_html: crate::app::markdown::render(&markup) + .wrap_err_with(|| format!("can't parse markdown for {:?}", path))?, date: { DateTime::<Utc>::from_utc( NaiveDateTime::new(date, NaiveTime::from_hms(0, 0, 0)), @@ -97,7 +100,7 @@ pub fn load(dir: &str) -> Result<Vec<Post>> { } if result.len() == 0 { - Err(anyhow!("no posts loaded")) + Err(eyre!("no posts loaded")) } else { result.sort(); result.reverse(); @@ -108,7 +111,7 @@ pub fn load(dir: &str) -> Result<Vec<Post>> { #[cfg(test)] mod tests { use super::*; - use anyhow::Result; + use color_eyre::eyre::Result; #[test] fn blog() { diff --git a/src/signalboost.rs b/src/signalboost.rs index 079990b..f580d7c 100644 --- a/src/signalboost.rs +++ b/src/signalboost.rs @@ -13,7 +13,7 @@ pub struct Person { #[cfg(test)] mod tests { - use anyhow::Result; + use color_eyre::eyre::Result; #[test] fn load() -> Result<()> { let _people: Vec<super::Person> = serde_dhall::from_file("./signalboost.dhall").parse()?; |
