aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristine Dodrill <me@christine.website>2020-09-19 11:33:46 -0400
committerGitHub <noreply@github.com>2020-09-19 11:33:46 -0400
commita2fba89738caac83ce24d40b762d6205f2266361 (patch)
tree3a61afb3b1a9d42b0a61b67be527322b6740f179 /src
parent1e61d2ad33f7ac7751063bdd373ab3d1305015e2 (diff)
downloadxesite-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.rs79
-rw-r--r--src/app/mod.rs (renamed from src/app.rs)24
-rw-r--r--src/main.rs3
-rw-r--r--src/post/frontmatter.rs2
-rw-r--r--src/post/mod.rs15
-rw-r--r--src/signalboost.rs2
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()?;