use std::borrow::Cow::{Owned, Borrowed}; use pulldown_cmark as cmark; use self::cmark::{Parser, Event, Tag, Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES}; use slug::slugify; use syntect::easy::HighlightLines; use syntect::html::{start_coloured_html_snippet, styles_to_coloured_html, IncludeBackground}; use errors::Result; use utils::site::resolve_internal_link; use highlighting::{get_highlighter, THEME_SET}; use link_checker::check_url; use table_of_contents::{TempHeader, Header, make_table_of_contents}; use context::RenderContext; const CONTINUE_READING: &str = "
\n"; #[derive(Debug)] pub struct Rendered { pub body: String, pub summary_len: Option or other things already there
temp_header.title += &text;
header_created = true;
return Event::Html(Borrowed(""));
}
// if we are in the middle of a code block
if let Some(ref mut highlighter) = highlighter {
let highlighted = &highlighter.highlight(&text);
let html = styles_to_coloured_html(highlighted, background);
return Event::Html(Owned(html));
}
// Business as usual
Event::Text(text)
}
Event::Start(Tag::CodeBlock(ref info)) => {
if !context.config.highlight_code {
return Event::Html(Borrowed(""));
}
let theme = &THEME_SET.themes[&context.config.highlight_theme];
match get_highlighter(&theme, info, context.base_path, &context.config.extra_syntaxes) {
Ok(h) => {
highlighter = Some(h);
// This selects the background color the same way that start_coloured_html_snippet does
let color = theme.settings.background.unwrap_or(::syntect::highlighting::Color::WHITE);
background = IncludeBackground::IfDifferent(color);
}
Err(err) => {
error = Some(format!("Could not load syntax: {}", err).into());
return Event::Html(Borrowed(""));
}
}
let snippet = start_coloured_html_snippet(theme);
Event::Html(Owned(snippet))
}
Event::End(Tag::CodeBlock(_)) => {
if !context.config.highlight_code {
return Event::Html(Borrowed("
\n"));
}
// reset highlight and close the code block
highlighter = None;
Event::Html(Borrowed(""))
}
Event::Start(Tag::Image(src, title)) => {
if is_colocated_asset_link(&src) {
return Event::Start(
Tag::Image(
Owned(format!("{}{}", context.current_page_permalink, src)),
title,
)
);
}
Event::Start(Tag::Image(src, title))
}
Event::Start(Tag::Link(link, title)) => {
// A few situations here:
// - it could be a relative link (starting with `./`)
// - it could be a link to a co-located asset
// - it could be a normal link
// - any of those can be in a header or not: if it's in a header
// we need to append to a string
let fixed_link = if link.starts_with("./") {
match resolve_internal_link(&link, context.permalinks) {
Ok(url) => url,
Err(_) => {
error = Some(format!("Relative link {} not found.", link).into());
return Event::Html(Borrowed(""));
}
}
} else if is_colocated_asset_link(&link) {
format!("{}{}", context.current_page_permalink, link)
} else {
if context.config.check_external_links && !link.starts_with('#') {
let res = check_url(&link);
if res.is_valid() {
link.to_string()
} else {
error = Some(
format!("Link {} is not valid: {}", link, res.message()).into()
);
String::new()
}
} else {
link.to_string()
}
};
if in_header {
let html = if title.is_empty() {
format!("", fixed_link)
} else {
format!("", fixed_link, title)
};
temp_header.push(&html);
return Event::Html(Borrowed(""));
}
Event::Start(Tag::Link(Owned(fixed_link), title))
}
Event::End(Tag::Link(_, _)) => {
if in_header {
temp_header.push("");
return Event::Html(Borrowed(""));
}
event
}
Event::Start(Tag::Code) => {
if in_header {
temp_header.push("");
return Event::Html(Borrowed(""));
}
event
}
Event::End(Tag::Code) => {
if in_header {
temp_header.push("
");
return Event::Html(Borrowed(""));
}
event
}
Event::Start(Tag::Header(num)) => {
in_header = true;
temp_header = TempHeader::new(num);
Event::Html(Borrowed(""))
}
Event::End(Tag::Header(_)) => {
// End of a header, reset all the things and return the stringified
// version of the header
in_header = false;
header_created = false;
let val = temp_header.to_string(context.tera, context.insert_anchor);
headers.push(temp_header.clone());
temp_header = TempHeader::default();
Event::Html(Owned(val))
}
Event::Html(ref markup) if markup.contains("") => {
has_summary = true;
Event::Html(Borrowed(CONTINUE_READING))
}
_ => event,
}
});
cmark::html::push_html(&mut html, parser);
}
if let Some(e) = error {
return Err(e)
} else {
html = html.replace("", "").replace("", "");
Ok(Rendered {
summary_len: if has_summary { html.find(CONTINUE_READING) } else { None },
body: html,
toc: make_table_of_contents(&headers)
})
}
}