diff --git a/README.md b/README.md index 67f04810..cb45fd6f 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,5 @@ markdown -> HTML for the content ### Themes Gallery at https://tmtheme-editor.herokuapp.com/#!/editor/theme/Agola%20Dark - -# TODO: - -- 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 +Make .themedump file: +`cargo run --example generate_themes themepack sublime_themes sublime_themes/all.themedump` diff --git a/examples/generate_themes.rs b/examples/generate_themes.rs new file mode 100644 index 00000000..880bb96d --- /dev/null +++ b/examples/generate_themes.rs @@ -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(), + } +} diff --git a/src/config.rs b/src/config.rs index 045f4fd0..c8a407bf 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,6 +6,7 @@ use std::collections::HashMap; use toml::{Value as Toml, self}; use errors::{Result, ResultExt}; +use markdown::SETUP; // TO ADD: @@ -22,6 +23,8 @@ pub struct Config { /// Whether to highlight all code blocks found in markdown files. Defaults to false pub highlight_code: Option, + /// Which themes to use for code highlighting. See Readme for supported themes + pub highlight_theme: Option, /// Description of the site pub description: Option, /// The language used in the site. Defaults to "en" @@ -50,6 +53,15 @@ impl Config { 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() { config.generate_rss = Some(false); } @@ -84,6 +96,7 @@ impl Default for Config { title: "".to_string(), base_url: "http://a-website.com/".to_string(), highlight_code: Some(true), + highlight_theme: Some("base16-ocean-dark".to_string()), description: None, language_code: Some("en".to_string()), generate_rss: Some(false), diff --git a/src/markdown.rs b/src/markdown.rs index 8bc6d339..873047fe 100644 --- a/src/markdown.rs +++ b/src/markdown.rs @@ -3,6 +3,7 @@ use std::borrow::Cow::Owned; use pulldown_cmark as cmark; use self::cmark::{Parser, Event, Tag}; +use syntect::dumps::from_binary; use syntect::easy::HighlightLines; use syntect::parsing::SyntaxSet; 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 -struct Setup { +pub struct Setup { syntax_set: SyntaxSet, - theme_set: ThemeSet, + pub theme_set: ThemeSet, } unsafe impl Send for Setup {} unsafe impl Sync for Setup {} lazy_static!{ - static ref SETUP: Setup = Setup { + pub static ref SETUP: Setup = Setup { 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 highlighter: Option>, parser: Parser<'a>, + theme: &'a str, } impl<'a> CodeHighlightingParser<'a> { - pub fn new(parser: Parser<'a>) -> CodeHighlightingParser<'a> { + pub fn new(parser: Parser<'a>, theme: &'a str) -> CodeHighlightingParser<'a> { CodeHighlightingParser { highlighter: None, parser: parser, + theme: theme, } } } @@ -67,15 +70,16 @@ impl<'a> Iterator for CodeHighlightingParser<'a> { } }, Event::Start(Tag::CodeBlock(ref info)) => { + let theme = &SETUP.theme_set.themes[self.theme]; let syntax = info .split(' ') .next() .and_then(|lang| SETUP.syntax_set.find_syntax_by_token(lang)) .unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text()); 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))) }, 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(); 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); } else { let parser = Parser::new(content); @@ -108,13 +112,13 @@ mod tests { #[test] 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, "

hello

\n"); } #[test] 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!( res, "
$ gutenberg server\n
\n" @@ -123,7 +127,7 @@ mod tests { #[test] 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!( res, "
\n$ gutenberg server\n$ ping\n
" @@ -132,7 +136,7 @@ mod tests { #[test] 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!( res, "
\nlist.append(1)\n
" @@ -140,7 +144,7 @@ mod tests { } #[test] 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 assert_eq!( res, diff --git a/src/page.rs b/src/page.rs index be7d6edf..f788aba3 100644 --- a/src/page.rs +++ b/src/page.rs @@ -132,12 +132,13 @@ impl Page { 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("") { page.summary = { let summary = page.raw_content.splitn(2, "").collect::>()[0]; - markdown_to_html(summary, should_highlight) + markdown_to_html(summary, should_highlight, &highlight_theme) } } diff --git a/sublime_themes/all.themedump b/sublime_themes/all.themedump new file mode 100644 index 00000000..3af3d02d Binary files /dev/null and b/sublime_themes/all.themedump differ