Add a rendering module
This commit is contained in:
parent
b2a63e2ada
commit
26159609d2
|
@ -6,7 +6,7 @@ use std::collections::HashMap;
|
||||||
use toml::{Value as Toml, self};
|
use toml::{Value as Toml, self};
|
||||||
|
|
||||||
use errors::{Result, ResultExt};
|
use errors::{Result, ResultExt};
|
||||||
use markdown::SETUP;
|
use rendering::highlighting::THEME_SET;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
@ -65,7 +65,7 @@ impl Config {
|
||||||
|
|
||||||
match config.highlight_theme {
|
match config.highlight_theme {
|
||||||
Some(ref t) => {
|
Some(ref t) => {
|
||||||
if !SETUP.theme_set.themes.contains_key(t) {
|
if !THEME_SET.themes.contains_key(t) {
|
||||||
bail!("Theme {} not available", t)
|
bail!("Theme {} not available", t)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,7 +11,7 @@ use slug::slugify;
|
||||||
use errors::{Result, ResultExt};
|
use errors::{Result, ResultExt};
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use front_matter::{PageFrontMatter, split_page_content};
|
use front_matter::{PageFrontMatter, split_page_content};
|
||||||
use markdown::markdown_to_html;
|
use rendering::markdown::markdown_to_html;
|
||||||
use fs::{read_file};
|
use fs::{read_file};
|
||||||
use content::utils::{find_related_assets, get_reading_analytics};
|
use content::utils::{find_related_assets, get_reading_analytics};
|
||||||
use content::file_info::FileInfo;
|
use content::file_info::FileInfo;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use config::Config;
|
||||||
use front_matter::{SectionFrontMatter, split_section_content};
|
use front_matter::{SectionFrontMatter, split_section_content};
|
||||||
use errors::{Result, ResultExt};
|
use errors::{Result, ResultExt};
|
||||||
use fs::{read_file};
|
use fs::{read_file};
|
||||||
use markdown::markdown_to_html;
|
use rendering::markdown::markdown_to_html;
|
||||||
use content::Page;
|
use content::Page;
|
||||||
use content::file_info::FileInfo;
|
use content::file_info::FileInfo;
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub mod errors;
|
||||||
mod front_matter;
|
mod front_matter;
|
||||||
mod content;
|
mod content;
|
||||||
mod site;
|
mod site;
|
||||||
mod markdown;
|
mod rendering;
|
||||||
// Filters, Global Fns and default instance of Tera
|
// Filters, Global Fns and default instance of Tera
|
||||||
mod templates;
|
mod templates;
|
||||||
|
|
||||||
|
@ -34,4 +34,3 @@ pub use config::{Config, get_config};
|
||||||
pub use front_matter::{PageFrontMatter, SectionFrontMatter, split_page_content, split_section_content};
|
pub use front_matter::{PageFrontMatter, SectionFrontMatter, split_page_content, split_section_content};
|
||||||
pub use content::{Page, Section, SortBy, sort_pages, populate_previous_and_next_pages};
|
pub use content::{Page, Section, SortBy, sort_pages, populate_previous_and_next_pages};
|
||||||
pub use fs::{create_file};
|
pub use fs::{create_file};
|
||||||
pub use markdown::markdown_to_html;
|
|
||||||
|
|
6
src/rendering/highlighting.rs
Normal file
6
src/rendering/highlighting.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
use syntect::dumps::from_binary;
|
||||||
|
use syntect::highlighting::ThemeSet;
|
||||||
|
|
||||||
|
lazy_static!{
|
||||||
|
pub static ref THEME_SET: ThemeSet = from_binary(include_bytes!("../../sublime_themes/all.themedump"));
|
||||||
|
}
|
|
@ -8,19 +8,18 @@ use slug::slugify;
|
||||||
use syntect::dumps::from_binary;
|
use syntect::dumps::from_binary;
|
||||||
use syntect::easy::HighlightLines;
|
use syntect::easy::HighlightLines;
|
||||||
use syntect::parsing::SyntaxSet;
|
use syntect::parsing::SyntaxSet;
|
||||||
use syntect::highlighting::ThemeSet;
|
|
||||||
use syntect::html::{start_coloured_html_snippet, styles_to_coloured_html, IncludeBackground};
|
use syntect::html::{start_coloured_html_snippet, styles_to_coloured_html, IncludeBackground};
|
||||||
use tera::{Tera, Context};
|
use tera::{Tera, Context};
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use errors::{Result, ResultExt};
|
use errors::{Result};
|
||||||
use site::resolve_internal_link;
|
use site::resolve_internal_link;
|
||||||
|
use rendering::highlighting::THEME_SET;
|
||||||
|
use rendering::short_code::{ShortCode, parse_shortcode, render_simple_shortcode};
|
||||||
|
|
||||||
// We need to put those in a struct to impl Send and sync
|
// We need to put those in a struct to impl Send and sync
|
||||||
pub struct Setup {
|
pub struct Setup {
|
||||||
pub syntax_set: SyntaxSet,
|
pub syntax_set: SyntaxSet,
|
||||||
pub theme_set: ThemeSet,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Setup {}
|
unsafe impl Send for Setup {}
|
||||||
|
@ -30,75 +29,13 @@ lazy_static!{
|
||||||
static ref SHORTCODE_RE: Regex = Regex::new(r#"\{(?:%|\{)\s+([[:alnum:]]+?)\(([[:alnum:]]+?="?.+?"?)\)\s+(?:%|\})\}"#).unwrap();
|
static ref SHORTCODE_RE: Regex = Regex::new(r#"\{(?:%|\{)\s+([[:alnum:]]+?)\(([[:alnum:]]+?="?.+?"?)\)\s+(?:%|\})\}"#).unwrap();
|
||||||
pub static ref SETUP: Setup = Setup {
|
pub static ref SETUP: Setup = Setup {
|
||||||
syntax_set: {
|
syntax_set: {
|
||||||
let mut ps: SyntaxSet = from_binary(include_bytes!("../sublime_syntaxes/newlines.packdump"));
|
let mut ps: SyntaxSet = from_binary(include_bytes!("../../sublime_syntaxes/newlines.packdump"));
|
||||||
ps.link_syntaxes();
|
ps.link_syntaxes();
|
||||||
ps
|
ps
|
||||||
},
|
},
|
||||||
theme_set: from_binary(include_bytes!("../sublime_themes/all.themedump"))
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A shortcode that has a body
|
|
||||||
/// Called by having some content like {% ... %} body {% end %}
|
|
||||||
/// We need the struct to hold the data while we're processing the markdown
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ShortCode {
|
|
||||||
name: String,
|
|
||||||
args: HashMap<String, String>,
|
|
||||||
body: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ShortCode {
|
|
||||||
pub fn new(name: &str, args: HashMap<String, String>) -> ShortCode {
|
|
||||||
ShortCode {
|
|
||||||
name: name.to_string(),
|
|
||||||
args: args,
|
|
||||||
body: String::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn append(&mut self, text: &str) {
|
|
||||||
self.body.push_str(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render(&self, tera: &Tera) -> Result<String> {
|
|
||||||
let mut context = Context::new();
|
|
||||||
for (key, value) in &self.args {
|
|
||||||
context.add(key, value);
|
|
||||||
}
|
|
||||||
context.add("body", &self.body);
|
|
||||||
let tpl_name = format!("shortcodes/{}.html", self.name);
|
|
||||||
tera.render(&tpl_name, &context)
|
|
||||||
.chain_err(|| format!("Failed to render {} shortcode", self.name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a shortcode without a body
|
|
||||||
fn parse_shortcode(input: &str) -> (String, HashMap<String, String>) {
|
|
||||||
let mut args = HashMap::new();
|
|
||||||
let caps = SHORTCODE_RE.captures(input).unwrap();
|
|
||||||
// caps[0] is the full match
|
|
||||||
let name = &caps[1];
|
|
||||||
let arg_list = &caps[2];
|
|
||||||
for arg in arg_list.split(',') {
|
|
||||||
let bits = arg.split('=').collect::<Vec<_>>();
|
|
||||||
args.insert(bits[0].trim().to_string(), bits[1].replace("\"", ""));
|
|
||||||
}
|
|
||||||
|
|
||||||
(name.to_string(), args)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Renders a shortcode or return an error
|
|
||||||
fn render_simple_shortcode(tera: &Tera, name: &str, args: &HashMap<String, String>) -> Result<String> {
|
|
||||||
let mut context = Context::new();
|
|
||||||
for (key, value) in args.iter() {
|
|
||||||
context.add(key, value);
|
|
||||||
}
|
|
||||||
let tpl_name = format!("shortcodes/{}.html", name);
|
|
||||||
|
|
||||||
tera.render(&tpl_name, &context).chain_err(|| format!("Failed to render {} shortcode", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn markdown_to_html(content: &str, permalinks: &HashMap<String, String>, tera: &Tera, config: &Config) -> Result<String> {
|
pub fn markdown_to_html(content: &str, permalinks: &HashMap<String, String>, tera: &Tera, config: &Config) -> Result<String> {
|
||||||
// We try to be smart about highlighting code as it can be time-consuming
|
// We try to be smart about highlighting code as it can be time-consuming
|
||||||
// If the global config disables it, then we do nothing. However,
|
// If the global config disables it, then we do nothing. However,
|
||||||
|
@ -233,7 +170,7 @@ pub fn markdown_to_html(content: &str, permalinks: &HashMap<String, String>, ter
|
||||||
if !should_highlight {
|
if !should_highlight {
|
||||||
return Event::Html(Owned("<pre><code>".to_owned()));
|
return Event::Html(Owned("<pre><code>".to_owned()));
|
||||||
}
|
}
|
||||||
let theme = &SETUP.theme_set.themes[&highlight_theme];
|
let theme = &THEME_SET.themes[&highlight_theme];
|
||||||
let syntax = info
|
let syntax = info
|
||||||
.split(' ')
|
.split(' ')
|
||||||
.next()
|
.next()
|
3
src/rendering/mod.rs
Normal file
3
src/rendering/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod highlighting;
|
||||||
|
pub mod markdown;
|
||||||
|
pub mod short_code;
|
71
src/rendering/short_code.rs
Normal file
71
src/rendering/short_code.rs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
use tera::{Tera, Context};
|
||||||
|
|
||||||
|
use errors::{Result, ResultExt};
|
||||||
|
|
||||||
|
lazy_static!{
|
||||||
|
static ref SHORTCODE_RE: Regex = Regex::new(r#"\{(?:%|\{)\s+([[:alnum:]]+?)\(([[:alnum:]]+?="?.+?"?)\)\s+(?:%|\})\}"#).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A shortcode that has a body
|
||||||
|
/// Called by having some content like {% ... %} body {% end %}
|
||||||
|
/// We need the struct to hold the data while we're processing the markdown
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ShortCode {
|
||||||
|
name: String,
|
||||||
|
args: HashMap<String, String>,
|
||||||
|
body: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShortCode {
|
||||||
|
pub fn new(name: &str, args: HashMap<String, String>) -> ShortCode {
|
||||||
|
ShortCode {
|
||||||
|
name: name.to_string(),
|
||||||
|
args: args,
|
||||||
|
body: String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append(&mut self, text: &str) {
|
||||||
|
self.body.push_str(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, tera: &Tera) -> Result<String> {
|
||||||
|
let mut context = Context::new();
|
||||||
|
for (key, value) in &self.args {
|
||||||
|
context.add(key, value);
|
||||||
|
}
|
||||||
|
context.add("body", &self.body);
|
||||||
|
let tpl_name = format!("shortcodes/{}.html", self.name);
|
||||||
|
tera.render(&tpl_name, &context)
|
||||||
|
.chain_err(|| format!("Failed to render {} shortcode", self.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a shortcode without a body
|
||||||
|
pub fn parse_shortcode(input: &str) -> (String, HashMap<String, String>) {
|
||||||
|
let mut args = HashMap::new();
|
||||||
|
let caps = SHORTCODE_RE.captures(input).unwrap();
|
||||||
|
// caps[0] is the full match
|
||||||
|
let name = &caps[1];
|
||||||
|
let arg_list = &caps[2];
|
||||||
|
for arg in arg_list.split(',') {
|
||||||
|
let bits = arg.split('=').collect::<Vec<_>>();
|
||||||
|
args.insert(bits[0].trim().to_string(), bits[1].replace("\"", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
(name.to_string(), args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Renders a shortcode or return an error
|
||||||
|
pub fn render_simple_shortcode(tera: &Tera, name: &str, args: &HashMap<String, String>) -> Result<String> {
|
||||||
|
let mut context = Context::new();
|
||||||
|
for (key, value) in args.iter() {
|
||||||
|
context.add(key, value);
|
||||||
|
}
|
||||||
|
let tpl_name = format!("shortcodes/{}.html", name);
|
||||||
|
|
||||||
|
tera.render(&tpl_name, &context).chain_err(|| format!("Failed to render {} shortcode", name))
|
||||||
|
}
|
Loading…
Reference in a new issue