|
@@ -3,6 +3,7 @@ use std::borrow::Cow::Owned; |
|
|
use pulldown_cmark as cmark; |
|
|
use pulldown_cmark as cmark; |
|
|
use self::cmark::{Parser, Event, Tag}; |
|
|
use self::cmark::{Parser, Event, Tag}; |
|
|
|
|
|
|
|
|
|
|
|
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::highlighting::ThemeSet; |
|
@@ -10,18 +11,18 @@ use syntect::html::{start_coloured_html_snippet, styles_to_coloured_html, Includ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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 |
|
|
struct Setup { |
|
|
|
|
|
|
|
|
pub struct Setup { |
|
|
syntax_set: SyntaxSet, |
|
|
syntax_set: SyntaxSet, |
|
|
theme_set: ThemeSet, |
|
|
|
|
|
|
|
|
pub theme_set: ThemeSet, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
unsafe impl Send for Setup {} |
|
|
unsafe impl Send for Setup {} |
|
|
unsafe impl Sync for Setup {} |
|
|
unsafe impl Sync for Setup {} |
|
|
|
|
|
|
|
|
lazy_static!{ |
|
|
lazy_static!{ |
|
|
static ref SETUP: Setup = Setup { |
|
|
|
|
|
|
|
|
pub static ref SETUP: Setup = Setup { |
|
|
syntax_set: SyntaxSet::load_defaults_newlines(), |
|
|
syntax_set: SyntaxSet::load_defaults_newlines(), |
|
|
theme_set: ThemeSet::load_defaults() |
|
|
|
|
|
|
|
|
theme_set: from_binary(include_bytes!("../sublime_themes/all.themedump")) |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -30,13 +31,15 @@ struct CodeHighlightingParser<'a> { |
|
|
// The block we're currently highlighting |
|
|
// The block we're currently highlighting |
|
|
highlighter: Option<HighlightLines<'a>>, |
|
|
highlighter: Option<HighlightLines<'a>>, |
|
|
parser: Parser<'a>, |
|
|
parser: Parser<'a>, |
|
|
|
|
|
theme: &'a str, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
impl<'a> CodeHighlightingParser<'a> { |
|
|
impl<'a> CodeHighlightingParser<'a> { |
|
|
pub fn new(parser: Parser<'a>) -> CodeHighlightingParser<'a> { |
|
|
|
|
|
|
|
|
pub fn new(parser: Parser<'a>, theme: &'a str) -> CodeHighlightingParser<'a> { |
|
|
CodeHighlightingParser { |
|
|
CodeHighlightingParser { |
|
|
highlighter: None, |
|
|
highlighter: None, |
|
|
parser: parser, |
|
|
parser: parser, |
|
|
|
|
|
theme: theme, |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@@ -67,15 +70,16 @@ impl<'a> Iterator for CodeHighlightingParser<'a> { |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
Event::Start(Tag::CodeBlock(ref info)) => { |
|
|
Event::Start(Tag::CodeBlock(ref info)) => { |
|
|
|
|
|
let theme = &SETUP.theme_set.themes[self.theme]; |
|
|
let syntax = info |
|
|
let syntax = info |
|
|
.split(' ') |
|
|
.split(' ') |
|
|
.next() |
|
|
.next() |
|
|
.and_then(|lang| SETUP.syntax_set.find_syntax_by_token(lang)) |
|
|
.and_then(|lang| SETUP.syntax_set.find_syntax_by_token(lang)) |
|
|
.unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text()); |
|
|
.unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text()); |
|
|
self.highlighter = Some( |
|
|
self.highlighter = Some( |
|
|
HighlightLines::new(syntax, &SETUP.theme_set.themes["base16-ocean.dark"]) |
|
|
|
|
|
|
|
|
HighlightLines::new(syntax, &theme) |
|
|
); |
|
|
); |
|
|
let snippet = start_coloured_html_snippet(&SETUP.theme_set.themes["base16-ocean.dark"]); |
|
|
|
|
|
|
|
|
let snippet = start_coloured_html_snippet(&theme); |
|
|
Some(Event::Html(Owned(snippet))) |
|
|
Some(Event::Html(Owned(snippet))) |
|
|
}, |
|
|
}, |
|
|
Event::End(Tag::CodeBlock(_)) => { |
|
|
Event::End(Tag::CodeBlock(_)) => { |
|
@@ -89,10 +93,10 @@ impl<'a> Iterator for CodeHighlightingParser<'a> { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
pub fn markdown_to_html(content: &str, highlight_code: bool) -> String { |
|
|
|
|
|
|
|
|
pub fn markdown_to_html(content: &str, highlight_code: bool, highlight_theme: &str) -> String { |
|
|
let mut html = String::new(); |
|
|
let mut html = String::new(); |
|
|
if highlight_code { |
|
|
if highlight_code { |
|
|
let parser = CodeHighlightingParser::new(Parser::new(content)); |
|
|
|
|
|
|
|
|
let parser = CodeHighlightingParser::new(Parser::new(content), highlight_theme); |
|
|
cmark::html::push_html(&mut html, parser); |
|
|
cmark::html::push_html(&mut html, parser); |
|
|
} else { |
|
|
} else { |
|
|
let parser = Parser::new(content); |
|
|
let parser = Parser::new(content); |
|
@@ -108,13 +112,13 @@ mod tests { |
|
|
|
|
|
|
|
|
#[test] |
|
|
#[test] |
|
|
fn test_markdown_to_html_simple() { |
|
|
fn test_markdown_to_html_simple() { |
|
|
let res = markdown_to_html("# hello", true); |
|
|
|
|
|
|
|
|
let res = markdown_to_html("# hello", true, "base16-ocean-dark"); |
|
|
assert_eq!(res, "<h1>hello</h1>\n"); |
|
|
assert_eq!(res, "<h1>hello</h1>\n"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[test] |
|
|
#[test] |
|
|
fn test_markdown_to_html_code_block_highlighting_off() { |
|
|
fn test_markdown_to_html_code_block_highlighting_off() { |
|
|
let res = markdown_to_html("```\n$ gutenberg server\n```", false); |
|
|
|
|
|
|
|
|
let res = markdown_to_html("```\n$ gutenberg server\n```", false, "base16-ocean-dark"); |
|
|
assert_eq!( |
|
|
assert_eq!( |
|
|
res, |
|
|
res, |
|
|
"<pre><code>$ gutenberg server\n</code></pre>\n" |
|
|
"<pre><code>$ gutenberg server\n</code></pre>\n" |
|
@@ -123,7 +127,7 @@ mod tests { |
|
|
|
|
|
|
|
|
#[test] |
|
|
#[test] |
|
|
fn test_markdown_to_html_code_block_no_lang() { |
|
|
fn test_markdown_to_html_code_block_no_lang() { |
|
|
let res = markdown_to_html("```\n$ gutenberg server\n$ ping\n```", true); |
|
|
|
|
|
|
|
|
let res = markdown_to_html("```\n$ gutenberg server\n$ ping\n```", true, "base16-ocean-dark"); |
|
|
assert_eq!( |
|
|
assert_eq!( |
|
|
res, |
|
|
res, |
|
|
"<pre style=\"background-color:#2b303b\">\n<span style=\"background-color:#2b303b;color:#c0c5ce;\">$ gutenberg server\n</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">$ ping\n</span></pre>" |
|
|
"<pre style=\"background-color:#2b303b\">\n<span style=\"background-color:#2b303b;color:#c0c5ce;\">$ gutenberg server\n</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">$ ping\n</span></pre>" |
|
@@ -132,7 +136,7 @@ mod tests { |
|
|
|
|
|
|
|
|
#[test] |
|
|
#[test] |
|
|
fn test_markdown_to_html_code_block_with_lang() { |
|
|
fn test_markdown_to_html_code_block_with_lang() { |
|
|
let res = markdown_to_html("```python\nlist.append(1)\n```", true); |
|
|
|
|
|
|
|
|
let res = markdown_to_html("```python\nlist.append(1)\n```", true, "base16-ocean-dark"); |
|
|
assert_eq!( |
|
|
assert_eq!( |
|
|
res, |
|
|
res, |
|
|
"<pre style=\"background-color:#2b303b\">\n<span style=\"background-color:#2b303b;color:#c0c5ce;\">list</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">.</span><span style=\"background-color:#2b303b;color:#bf616a;\">append</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">(</span><span style=\"background-color:#2b303b;color:#d08770;\">1</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">)</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">\n</span></pre>" |
|
|
"<pre style=\"background-color:#2b303b\">\n<span style=\"background-color:#2b303b;color:#c0c5ce;\">list</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">.</span><span style=\"background-color:#2b303b;color:#bf616a;\">append</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">(</span><span style=\"background-color:#2b303b;color:#d08770;\">1</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">)</span><span style=\"background-color:#2b303b;color:#c0c5ce;\">\n</span></pre>" |
|
@@ -140,7 +144,7 @@ mod tests { |
|
|
} |
|
|
} |
|
|
#[test] |
|
|
#[test] |
|
|
fn test_markdown_to_html_code_block_with_unknown_lang() { |
|
|
fn test_markdown_to_html_code_block_with_unknown_lang() { |
|
|
let res = markdown_to_html("```yolo\nlist.append(1)\n```", true); |
|
|
|
|
|
|
|
|
let res = markdown_to_html("```yolo\nlist.append(1)\n```", true, "base16-ocean-dark"); |
|
|
// defaults to plain text |
|
|
// defaults to plain text |
|
|
assert_eq!( |
|
|
assert_eq!( |
|
|
res, |
|
|
res, |
|
|