Pick highlighting theme from config

This commit is contained in:
Vincent Prouillet 2017-03-20 17:30:50 +09:00
parent 81596af366
commit 9af85ba3e4
6 changed files with 81 additions and 23 deletions

View file

@ -34,10 +34,5 @@ markdown -> HTML for the content
### Themes ### Themes
Gallery at https://tmtheme-editor.herokuapp.com/#!/editor/theme/Agola%20Dark Gallery at https://tmtheme-editor.herokuapp.com/#!/editor/theme/Agola%20Dark
Make .themedump file:
# TODO: `cargo run --example generate_themes themepack sublime_themes sublime_themes/all.themedump`
- find a way to add tests
- syntax highlighting
- pass a --config arg to the CLI to change from `config.toml`
- have verbosity levels with a `verbosity` config variable with a default

View file

@ -0,0 +1,45 @@
//! This program is mainly intended for generating the dumps that are compiled in to
//! syntect, not as a helpful example for beginners.
//! Although it is a valid example for serializing syntaxes, you probably won't need
//! to do this yourself unless you want to cache your own compiled grammars.
extern crate syntect;
use syntect::parsing::SyntaxSet;
use syntect::highlighting::ThemeSet;
use syntect::dumps::*;
use std::env;
fn usage_and_exit() -> ! {
println!("USAGE: gendata synpack source-dir newlines.packdump nonewlines.packdump\n
gendata themepack source-dir themepack.themedump");
::std::process::exit(2);
}
fn main() {
let mut a = env::args().skip(1);
match (a.next(), a.next(), a.next(), a.next()) {
(Some(ref cmd),
Some(ref package_dir),
Some(ref packpath_newlines),
Some(ref packpath_nonewlines)) if cmd == "synpack" => {
let mut ps = SyntaxSet::new();
ps.load_plain_text_syntax();
ps.load_syntaxes(package_dir, true).unwrap();
dump_to_file(&ps, packpath_newlines).unwrap();
ps = SyntaxSet::new();
ps.load_plain_text_syntax();
ps.load_syntaxes(package_dir, false).unwrap();
dump_to_file(&ps, packpath_nonewlines).unwrap();
}
(Some(ref s), Some(ref theme_dir), Some(ref packpath), None) if s == "themepack" => {
let ts = ThemeSet::load_from_folder(theme_dir).unwrap();
for (path, _) in &ts.themes {
println!("{:?}", path);
}
dump_to_file(&ts, packpath).unwrap();
}
_ => usage_and_exit(),
}
}

View file

@ -6,6 +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;
// TO ADD: // TO ADD:
@ -22,6 +23,8 @@ pub struct Config {
/// Whether to highlight all code blocks found in markdown files. Defaults to false /// Whether to highlight all code blocks found in markdown files. Defaults to false
pub highlight_code: Option<bool>, pub highlight_code: Option<bool>,
/// Which themes to use for code highlighting. See Readme for supported themes
pub highlight_theme: Option<String>,
/// Description of the site /// Description of the site
pub description: Option<String>, pub description: Option<String>,
/// The language used in the site. Defaults to "en" /// The language used in the site. Defaults to "en"
@ -50,6 +53,15 @@ impl Config {
config.highlight_code = Some(false); config.highlight_code = Some(false);
} }
match config.highlight_theme {
Some(ref t) => {
if !SETUP.theme_set.themes.contains_key(t) {
bail!("Theme {} not available", t)
}
},
None => config.highlight_theme = Some("base16-ocean-dark".to_string())
};
if config.generate_rss.is_none() { if config.generate_rss.is_none() {
config.generate_rss = Some(false); config.generate_rss = Some(false);
} }
@ -84,6 +96,7 @@ impl Default for Config {
title: "".to_string(), title: "".to_string(),
base_url: "http://a-website.com/".to_string(), base_url: "http://a-website.com/".to_string(),
highlight_code: Some(true), highlight_code: Some(true),
highlight_theme: Some("base16-ocean-dark".to_string()),
description: None, description: None,
language_code: Some("en".to_string()), language_code: Some("en".to_string()),
generate_rss: Some(false), generate_rss: Some(false),

View file

@ -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,

View file

@ -132,12 +132,13 @@ impl Page {
false false
}; };
page.content = markdown_to_html(&page.raw_content, should_highlight); let highlight_theme = config.highlight_theme.clone().unwrap();
page.content = markdown_to_html(&page.raw_content, should_highlight, &highlight_theme);
if page.raw_content.contains("<!-- more -->") { if page.raw_content.contains("<!-- more -->") {
page.summary = { page.summary = {
let summary = page.raw_content.splitn(2, "<!-- more -->").collect::<Vec<&str>>()[0]; let summary = page.raw_content.splitn(2, "<!-- more -->").collect::<Vec<&str>>()[0];
markdown_to_html(summary, should_highlight) markdown_to_html(summary, should_highlight, &highlight_theme)
} }
} }

Binary file not shown.