Support custom syntax highlighting themes (#1499)
Related to #419 Gruvbox tmTheme added to test_site, it is taken from https://github.com/Colorsublime/Colorsublime-Themes (MIT licensed)
This commit is contained in:
parent
f0b131838f
commit
23064f57c8
@ -1,9 +1,15 @@
|
|||||||
use std::path::Path;
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use syntect::parsing::{SyntaxSet, SyntaxSetBuilder};
|
use syntect::{
|
||||||
|
highlighting::{Theme, ThemeSet},
|
||||||
|
html::css_for_theme_with_class_style,
|
||||||
|
parsing::{SyntaxSet, SyntaxSetBuilder},
|
||||||
|
};
|
||||||
|
|
||||||
use errors::Result;
|
use errors::{bail, Result};
|
||||||
|
|
||||||
|
use crate::highlighting::{CLASS_STYLE, THEME_SET};
|
||||||
|
|
||||||
pub const DEFAULT_HIGHLIGHT_THEME: &str = "base16-ocean-dark";
|
pub const DEFAULT_HIGHLIGHT_THEME: &str = "base16-ocean-dark";
|
||||||
|
|
||||||
@ -43,26 +49,92 @@ pub struct Markdown {
|
|||||||
pub external_links_no_referrer: bool,
|
pub external_links_no_referrer: bool,
|
||||||
/// Whether smart punctuation is enabled (changing quotes, dashes, dots etc in their typographic form)
|
/// Whether smart punctuation is enabled (changing quotes, dashes, dots etc in their typographic form)
|
||||||
pub smart_punctuation: bool,
|
pub smart_punctuation: bool,
|
||||||
|
/// A list of directories to search for additional `.sublime-syntax` and `.tmTheme` files in.
|
||||||
/// A list of directories to search for additional `.sublime-syntax` files in.
|
pub extra_syntaxes_and_themes: Vec<String>,
|
||||||
pub extra_syntaxes: Vec<String>,
|
|
||||||
/// The compiled extra syntaxes into a syntax set
|
/// The compiled extra syntaxes into a syntax set
|
||||||
#[serde(skip_serializing, skip_deserializing)] // not a typo, 2 are need
|
#[serde(skip_serializing, skip_deserializing)] // not a typo, 2 are need
|
||||||
pub extra_syntax_set: Option<SyntaxSet>,
|
pub extra_syntax_set: Option<SyntaxSet>,
|
||||||
|
/// The compiled extra themes into a theme set
|
||||||
|
#[serde(skip_serializing, skip_deserializing)] // not a typo, 2 are need
|
||||||
|
pub extra_theme_set: Arc<Option<ThemeSet>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Markdown {
|
impl Markdown {
|
||||||
/// Attempt to load any extra syntax found in the extra syntaxes of the config
|
/// Gets the configured highlight theme from the THEME_SET or the config's extra_theme_set
|
||||||
pub fn load_extra_syntaxes(&mut self, base_path: &Path) -> Result<()> {
|
/// Returns None if the configured highlighting theme is set to use css
|
||||||
if self.extra_syntaxes.is_empty() {
|
pub fn get_highlight_theme(&self) -> Option<&Theme> {
|
||||||
return Ok(());
|
if self.highlight_theme == "css" {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.get_highlight_theme_by_name(&self.highlight_theme))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an arbitrary theme from the THEME_SET or the extra_theme_set
|
||||||
|
pub fn get_highlight_theme_by_name<'config>(&'config self, theme_name: &str) -> &'config Theme {
|
||||||
|
(*self.extra_theme_set)
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|ts| ts.themes.get(theme_name))
|
||||||
|
.unwrap_or_else(|| &THEME_SET.themes[theme_name])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt to load any extra syntaxes and themes found in the extra_syntaxes_and_themes folders
|
||||||
|
pub fn load_extra_syntaxes_and_highlight_themes(
|
||||||
|
&self,
|
||||||
|
base_path: &Path,
|
||||||
|
) -> Result<(Option<SyntaxSet>, Option<ThemeSet>)> {
|
||||||
|
if self.extra_syntaxes_and_themes.is_empty() {
|
||||||
|
return Ok((None, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ss = SyntaxSetBuilder::new();
|
let mut ss = SyntaxSetBuilder::new();
|
||||||
for dir in &self.extra_syntaxes {
|
let mut ts = ThemeSet::new();
|
||||||
|
for dir in &self.extra_syntaxes_and_themes {
|
||||||
ss.add_from_folder(base_path.join(dir), true)?;
|
ss.add_from_folder(base_path.join(dir), true)?;
|
||||||
|
ts.add_from_folder(base_path.join(dir))?;
|
||||||
|
}
|
||||||
|
let ss = ss.build();
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
if ss.syntaxes().is_empty() { None } else { Some(ss) },
|
||||||
|
if ts.themes.is_empty() { None } else { Some(ts) },
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn export_theme_css(&self, theme_name: &str) -> String {
|
||||||
|
let theme = self.get_highlight_theme_by_name(theme_name);
|
||||||
|
css_for_theme_with_class_style(theme, CLASS_STYLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_extra_syntaxes_and_highlight_themes(&mut self, path: &Path) -> Result<()> {
|
||||||
|
if self.highlight_theme == "css" {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let (loaded_extra_syntaxes, loaded_extra_highlight_themes) =
|
||||||
|
self.load_extra_syntaxes_and_highlight_themes(path)?;
|
||||||
|
|
||||||
|
if let Some(extra_syntax_set) = loaded_extra_syntaxes {
|
||||||
|
self.extra_syntax_set = Some(extra_syntax_set);
|
||||||
|
}
|
||||||
|
if let Some(extra_theme_set) = loaded_extra_highlight_themes {
|
||||||
|
self.extra_theme_set = Arc::new(Some(extra_theme_set));
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate that the chosen highlight_theme exists in the loaded highlight theme sets
|
||||||
|
if !THEME_SET.themes.contains_key(&self.highlight_theme) {
|
||||||
|
if let Some(extra) = &*self.extra_theme_set {
|
||||||
|
if !extra.themes.contains_key(&self.highlight_theme) {
|
||||||
|
bail!(
|
||||||
|
"Highlight theme {} not found in the extra theme set",
|
||||||
|
self.highlight_theme
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bail!("Highlight theme {} not available.\n\
|
||||||
|
You can load custom themes by configuring `extra_syntaxes_and_themes` to include a list of folders containing '.tmTheme' files", self.highlight_theme)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.extra_syntax_set = Some(ss.build());
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -110,8 +182,9 @@ impl Default for Markdown {
|
|||||||
external_links_no_follow: false,
|
external_links_no_follow: false,
|
||||||
external_links_no_referrer: false,
|
external_links_no_referrer: false,
|
||||||
smart_punctuation: false,
|
smart_punctuation: false,
|
||||||
extra_syntaxes: Vec::new(),
|
extra_syntaxes_and_themes: vec![],
|
||||||
extra_syntax_set: None,
|
extra_syntax_set: None,
|
||||||
|
extra_theme_set: Arc::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ use globset::{Glob, GlobSet, GlobSetBuilder};
|
|||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use toml::Value as Toml;
|
use toml::Value as Toml;
|
||||||
|
|
||||||
use crate::highlighting::THEME_SET;
|
|
||||||
use crate::theme::Theme;
|
use crate::theme::Theme;
|
||||||
use errors::{bail, Error, Result};
|
use errors::{bail, Error, Result};
|
||||||
use utils::fs::read_file;
|
use utils::fs::read_file;
|
||||||
@ -106,6 +105,7 @@ pub struct SerializedConfig<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
// any extra syntax and highlight themes have been loaded and validated already by the from_file method before parsing the config
|
||||||
/// Parses a string containing TOML to our Config struct
|
/// Parses a string containing TOML to our Config struct
|
||||||
/// Any extra parameter will end up in the extra field
|
/// Any extra parameter will end up in the extra field
|
||||||
pub fn parse(content: &str) -> Result<Config> {
|
pub fn parse(content: &str) -> Result<Config> {
|
||||||
@ -118,15 +118,6 @@ impl Config {
|
|||||||
bail!("A base URL is required in config.toml with key `base_url`");
|
bail!("A base URL is required in config.toml with key `base_url`");
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.markdown.highlight_theme != "css"
|
|
||||||
&& !THEME_SET.themes.contains_key(&config.markdown.highlight_theme)
|
|
||||||
{
|
|
||||||
bail!(
|
|
||||||
"Highlight theme {} defined in config does not exist.",
|
|
||||||
config.markdown.highlight_theme
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
languages::validate_code(&config.default_language)?;
|
languages::validate_code(&config.default_language)?;
|
||||||
for code in config.languages.keys() {
|
for code in config.languages.keys() {
|
||||||
languages::validate_code(code)?;
|
languages::validate_code(code)?;
|
||||||
@ -166,7 +157,16 @@ impl Config {
|
|||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let content =
|
let content =
|
||||||
read_file(path).map_err(|e| errors::Error::chain("Failed to load config", e))?;
|
read_file(path).map_err(|e| errors::Error::chain("Failed to load config", e))?;
|
||||||
Config::parse(&content)
|
|
||||||
|
let mut config = Config::parse(&content)?;
|
||||||
|
let config_dir = path
|
||||||
|
.parent()
|
||||||
|
.ok_or(Error::msg("Failed to find directory containing the config file."))?;
|
||||||
|
|
||||||
|
// this is the step at which missing extra syntax and highlighting themes are raised as errors
|
||||||
|
config.markdown.init_extra_syntaxes_and_highlight_themes(config_dir)?;
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a url, taking into account that the base url might have a trailing slash
|
/// Makes a url, taking into account that the base url might have a trailing slash
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use syntect::dumps::from_binary;
|
use syntect::dumps::from_binary;
|
||||||
use syntect::highlighting::{Theme, ThemeSet};
|
use syntect::highlighting::{Theme, ThemeSet};
|
||||||
|
use syntect::html::ClassStyle;
|
||||||
use syntect::parsing::{SyntaxReference, SyntaxSet};
|
use syntect::parsing::{SyntaxReference, SyntaxSet};
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use syntect::html::{css_for_theme_with_class_style, ClassStyle};
|
|
||||||
|
pub const CLASS_STYLE: ClassStyle = ClassStyle::SpacedPrefixed { prefix: "z-" };
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref SYNTAX_SET: SyntaxSet = {
|
pub static ref SYNTAX_SET: SyntaxSet = {
|
||||||
@ -16,8 +18,6 @@ lazy_static! {
|
|||||||
from_binary(include_bytes!("../../../sublime/themes/all.themedump"));
|
from_binary(include_bytes!("../../../sublime/themes/all.themedump"));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CLASS_STYLE: ClassStyle = ClassStyle::SpacedPrefixed { prefix: "z-" };
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum HighlightSource {
|
pub enum HighlightSource {
|
||||||
/// One of the built-in Zola syntaxes
|
/// One of the built-in Zola syntaxes
|
||||||
@ -42,11 +42,7 @@ pub fn resolve_syntax_and_theme<'config>(
|
|||||||
language: Option<&'_ str>,
|
language: Option<&'_ str>,
|
||||||
config: &'config Config,
|
config: &'config Config,
|
||||||
) -> SyntaxAndTheme<'config> {
|
) -> SyntaxAndTheme<'config> {
|
||||||
let theme = if config.markdown.highlight_theme != "css" {
|
let theme = config.markdown.get_highlight_theme();
|
||||||
Some(&THEME_SET.themes[&config.markdown.highlight_theme])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(ref lang) = language {
|
if let Some(ref lang) = language {
|
||||||
if let Some(ref extra_syntaxes) = config.markdown.extra_syntax_set {
|
if let Some(ref extra_syntaxes) = config.markdown.extra_syntax_set {
|
||||||
@ -88,8 +84,3 @@ pub fn resolve_syntax_and_theme<'config>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn export_theme_css(theme_name: &str) -> String {
|
|
||||||
let theme = &THEME_SET.themes[theme_name];
|
|
||||||
css_for_theme_with_class_style(theme, CLASS_STYLE)
|
|
||||||
}
|
|
||||||
|
@ -106,10 +106,11 @@ fn bench_render_content_without_highlighting(b: &mut test::Bencher) {
|
|||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.markdown.highlight_code = false;
|
config.markdown.highlight_code = false;
|
||||||
let current_page_permalink = "";
|
let current_page_permalink = "";
|
||||||
|
let lang = "";
|
||||||
let context = RenderContext::new(
|
let context = RenderContext::new(
|
||||||
&tera,
|
&tera,
|
||||||
&config,
|
&config,
|
||||||
"",
|
lang,
|
||||||
current_page_permalink,
|
current_page_permalink,
|
||||||
&permalinks_ctx,
|
&permalinks_ctx,
|
||||||
InsertAnchor::None,
|
InsertAnchor::None,
|
||||||
@ -117,7 +118,6 @@ fn bench_render_content_without_highlighting(b: &mut test::Bencher) {
|
|||||||
b.iter(|| render_content(CONTENT, &context).unwrap());
|
b.iter(|| render_content(CONTENT, &context).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_render_content_no_shortcode(b: &mut test::Bencher) {
|
fn bench_render_content_no_shortcode(b: &mut test::Bencher) {
|
||||||
let tera = Tera::default();
|
let tera = Tera::default();
|
||||||
let content2 = CONTENT.replace(r#"{{ youtube(id="my_youtube_id") }}"#, "");
|
let content2 = CONTENT.replace(r#"{{ youtube(id="my_youtube_id") }}"#, "");
|
||||||
@ -125,10 +125,11 @@ fn bench_render_content_no_shortcode(b: &mut test::Bencher) {
|
|||||||
config.markdown.highlight_code = false;
|
config.markdown.highlight_code = false;
|
||||||
let permalinks_ctx = HashMap::new();
|
let permalinks_ctx = HashMap::new();
|
||||||
let current_page_permalink = "";
|
let current_page_permalink = "";
|
||||||
|
let lang = "";
|
||||||
let context = RenderContext::new(
|
let context = RenderContext::new(
|
||||||
&tera,
|
&tera,
|
||||||
&config,
|
&config,
|
||||||
"",
|
lang,
|
||||||
current_page_permalink,
|
current_page_permalink,
|
||||||
&permalinks_ctx,
|
&permalinks_ctx,
|
||||||
InsertAnchor::None,
|
InsertAnchor::None,
|
||||||
@ -144,16 +145,15 @@ fn bench_render_shortcodes_one_present(b: &mut test::Bencher) {
|
|||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let permalinks_ctx = HashMap::new();
|
let permalinks_ctx = HashMap::new();
|
||||||
let current_page_permalink = "";
|
let current_page_permalink = "";
|
||||||
|
let lang = "";
|
||||||
let context = RenderContext::new(
|
let context = RenderContext::new(
|
||||||
&tera,
|
&tera,
|
||||||
&config,
|
&config,
|
||||||
"",
|
lang,
|
||||||
current_page_permalink,
|
current_page_permalink,
|
||||||
&permalinks_ctx,
|
&permalinks_ctx,
|
||||||
InsertAnchor::None,
|
InsertAnchor::None,
|
||||||
);
|
);
|
||||||
|
|
||||||
b.iter(|| render_shortcodes(CONTENT, &context));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
@ -165,10 +165,11 @@ fn bench_render_content_no_shortcode_with_emoji(b: &mut test::Bencher) {
|
|||||||
config.markdown.render_emoji = true;
|
config.markdown.render_emoji = true;
|
||||||
let permalinks_ctx = HashMap::new();
|
let permalinks_ctx = HashMap::new();
|
||||||
let current_page_permalink = "";
|
let current_page_permalink = "";
|
||||||
|
let lang = "";
|
||||||
let context = RenderContext::new(
|
let context = RenderContext::new(
|
||||||
&tera,
|
&tera,
|
||||||
&config,
|
&config,
|
||||||
"",
|
lang,
|
||||||
current_page_permalink,
|
current_page_permalink,
|
||||||
&permalinks_ctx,
|
&permalinks_ctx,
|
||||||
InsertAnchor::None,
|
InsertAnchor::None,
|
||||||
|
@ -26,7 +26,7 @@ pub(crate) struct ClassHighlighter<'config> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'config> ClassHighlighter<'config> {
|
impl<'config> ClassHighlighter<'config> {
|
||||||
pub fn new(syntax: &'config SyntaxReference, syntax_set: &'config SyntaxSet) -> Self {
|
pub fn new(syntax: &SyntaxReference, syntax_set: &'config SyntaxSet) -> Self {
|
||||||
let parse_state = ParseState::new(syntax);
|
let parse_state = ParseState::new(syntax);
|
||||||
Self { syntax_set, open_spans: 0, parse_state, scope_stack: ScopeStack::new() }
|
Self { syntax_set, open_spans: 0, parse_state, scope_stack: ScopeStack::new() }
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ use rayon::prelude::*;
|
|||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
use walkdir::{DirEntry, WalkDir};
|
use walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
use config::highlighting::export_theme_css;
|
|
||||||
use config::{get_config, Config};
|
use config::{get_config, Config};
|
||||||
use errors::{bail, Error, Result};
|
use errors::{bail, Error, Result};
|
||||||
use front_matter::InsertAnchor;
|
use front_matter::InsertAnchor;
|
||||||
@ -74,7 +73,7 @@ impl Site {
|
|||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let config_file = config_file.as_ref();
|
let config_file = config_file.as_ref();
|
||||||
let mut config = get_config(config_file)?;
|
let mut config = get_config(config_file)?;
|
||||||
config.markdown.load_extra_syntaxes(path)?;
|
config.markdown.load_extra_syntaxes_and_highlight_themes(path)?;
|
||||||
|
|
||||||
if let Some(theme) = config.theme.clone() {
|
if let Some(theme) = config.theme.clone() {
|
||||||
// Grab data from the extra section of the theme
|
// Grab data from the extra section of the theme
|
||||||
@ -691,7 +690,7 @@ impl Site {
|
|||||||
for t in &self.config.markdown.highlight_themes_css {
|
for t in &self.config.markdown.highlight_themes_css {
|
||||||
let p = self.static_path.join(&t.filename);
|
let p = self.static_path.join(&t.filename);
|
||||||
if !p.exists() {
|
if !p.exists() {
|
||||||
let content = export_theme_css(&t.theme);
|
let content = &self.config.markdown.export_theme_css(&t.theme);
|
||||||
create_file(&p, &content)?;
|
create_file(&p, &content)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ Here is a full list of supported languages and their short names:
|
|||||||
Note: due to some issues with the JavaScript syntax, the TypeScript syntax will be used instead.
|
Note: due to some issues with the JavaScript syntax, the TypeScript syntax will be used instead.
|
||||||
|
|
||||||
If you want to highlight a language not on this list, please open an issue or a pull request on the [Zola repo](https://github.com/getzola/zola).
|
If you want to highlight a language not on this list, please open an issue or a pull request on the [Zola repo](https://github.com/getzola/zola).
|
||||||
Alternatively, the `extra_syntaxes` configuration option can be used to add additional syntax files.
|
Alternatively, the `extra_syntaxes_and_themes` configuration option can be used to add additional syntax (and theme) files.
|
||||||
|
|
||||||
If your site source is laid out as follows:
|
If your site source is laid out as follows:
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ If your site source is laid out as follows:
|
|||||||
└── ...
|
└── ...
|
||||||
```
|
```
|
||||||
|
|
||||||
you would set your `extra_syntaxes` to `["syntaxes", "syntaxes/Sublime-Language1"]` to load `lang1.sublime-syntax` and `lang2.sublime-syntax`.
|
you would set your `extra_syntaxes_and_themes` to `["syntaxes", "syntaxes/Sublime-Language1"]` to load `lang1.sublime-syntax` and `lang2.sublime-syntax`.
|
||||||
|
|
||||||
## Inline VS classed highlighting
|
## Inline VS classed highlighting
|
||||||
|
|
||||||
@ -347,3 +347,40 @@ Line 2 and 7 are comments that are not shown in the final output.
|
|||||||
|
|
||||||
When line numbers are active, the code block is turned into a table with one row and two cells. The first cell contains the line number and the second cell contains the code.
|
When line numbers are active, the code block is turned into a table with one row and two cells. The first cell contains the line number and the second cell contains the code.
|
||||||
Highlights are done via the `<mark>` HTML tag. When a line with line number is highlighted two `<mark>` tags are created: one around the line number(s) and one around the code.
|
Highlights are done via the `<mark>` HTML tag. When a line with line number is highlighted two `<mark>` tags are created: one around the line number(s) and one around the code.
|
||||||
|
|
||||||
|
## Custom Highlighting Themes
|
||||||
|
|
||||||
|
The default *theme* for syntax highlighting is called `base16-ocean-dark`, you can choose another theme from the built in set of highlight themes using the `highlight_theme` configuration option.
|
||||||
|
For example, this documentation site currently uses the `kronuz` theme, which is built in.
|
||||||
|
|
||||||
|
```
|
||||||
|
[markdown]
|
||||||
|
highlight_code = true
|
||||||
|
highlight_theme = "kronuz"
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, the `extra_syntaxes_and_themes` configuration option can be used to add additional theme files.
|
||||||
|
You can load your own highlight theme from a TextMate `.tmTheme` file.
|
||||||
|
|
||||||
|
It works the same way as adding extra syntaxes. It should contain a list of paths to folders containing the .tmTheme files you want to include.
|
||||||
|
You would then set `highlight_theme` to the name of one of these files, without the `.tmTheme` extension.
|
||||||
|
|
||||||
|
If your site source is laid out as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── config.toml
|
||||||
|
├── content/
|
||||||
|
│ └── ...
|
||||||
|
├── static/
|
||||||
|
│ └── ...
|
||||||
|
├── highlight_themes/
|
||||||
|
│ ├── MyGroovyTheme/
|
||||||
|
│ │ └── theme1.tmTheme
|
||||||
|
│ ├── theme2.tmTheme
|
||||||
|
└── templates/
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
you would set your `extra_highlight_themes` to `["highlight_themes", "highlight_themes/MyGroovyTheme"]` to load `theme1.tmTheme` and `theme2.tmTheme`.
|
||||||
|
Then choose one of them to use, say theme1, by setting `highlight_theme = theme1`.
|
||||||
|
@ -236,6 +236,9 @@ Zola currently has the following highlight themes available:
|
|||||||
Zola uses the Sublime Text themes, making it very easy to add more.
|
Zola uses the Sublime Text themes, making it very easy to add more.
|
||||||
If you want a theme not listed above, please open an issue or a pull request on the [Zola repo](https://github.com/getzola/zola).
|
If you want a theme not listed above, please open an issue or a pull request on the [Zola repo](https://github.com/getzola/zola).
|
||||||
|
|
||||||
|
Alternatively you can use the `extra_syntaxes_and_themes` configuration option to load your own custom themes from a .tmTheme file.
|
||||||
|
See [Syntax Highlighting](@/syntax-highlighting.md) for more details.
|
||||||
|
|
||||||
## Slugification strategies
|
## Slugification strategies
|
||||||
|
|
||||||
By default, Zola will turn every path, taxonomies and anchors to a slug, an ASCII representation with no special characters.
|
By default, Zola will turn every path, taxonomies and anchors to a slug, an ASCII representation with no special characters.
|
||||||
|
@ -13,7 +13,8 @@ ignored_content = ["*/ignored.md"]
|
|||||||
|
|
||||||
[markdown]
|
[markdown]
|
||||||
highlight_code = true
|
highlight_code = true
|
||||||
extra_syntaxes = ["syntaxes"]
|
highlight_theme = "custom_gruvbox"
|
||||||
|
extra_syntaxes_and_themes = ["syntaxes", "highlight_themes"]
|
||||||
|
|
||||||
[slugify]
|
[slugify]
|
||||||
paths = "on"
|
paths = "on"
|
||||||
|
@ -10,6 +10,12 @@ for (int i = 0; ; i++ ) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
for (int i = 0; ; i++ ) {
|
||||||
|
if (i < 10)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```c
|
```c
|
||||||
for (int i = 0; ; i++ ) {
|
for (int i = 0; ; i++ ) {
|
||||||
if (i < 10)
|
if (i < 10)
|
||||||
|
394
test_site/highlight_themes/custom_gruvbox.tmTheme
Normal file
394
test_site/highlight_themes/custom_gruvbox.tmTheme
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Gruvbox-N</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#1a1a1a</string>
|
||||||
|
<key>caret</key>
|
||||||
|
<string>#908476</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#EAD4AF</string>
|
||||||
|
<key>invisibles</key>
|
||||||
|
<string>#3B3836</string>
|
||||||
|
<key>lineHighlight</key>
|
||||||
|
<string>#3B3836</string>
|
||||||
|
<key>selection</key>
|
||||||
|
<string>#3B3836</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Comment</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>comment</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#908476</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>String</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#AAB11E</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Separator</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.separator.key-value</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#CF8498</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Constant</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#CC869B</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#EAD4AF</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Other variable objct</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.other.object</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#CAB990</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Other variable class</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.other.class, variable.other.constant</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F1C050</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Object property</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.property.object, entity.name.tag</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#EAD4AF</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Arrows</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.function, meta.function.static.arrow, meta.function.arrow</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#EAD4AF</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Keyword</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword, string.regexp punctuation.definition</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FB4938</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage, storage.type</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FB4938</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Inline link</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.underline.link</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FB4938</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Class name</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.class, entity.name.type.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#BABC52</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Inherited class</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.other.inherited-class, tag.decorator, tag.decorator entity.name.tag</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#7BA093</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Function name</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.function, meta.function entity.name.function</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8AB572</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Function argument</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.parameter, meta.function storage.type</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FD971F</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Tag name</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.tag</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FB4938</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string> italic </string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Tag attribute</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.other.attribute-name</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8AB572</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string> italic</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Library class/type</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.type, support.class, support.function, variable.language, support.constant, string.regexp keyword.control</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F1C050</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Template string element</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.template-string.element, string.regexp punctuation.definition.group, constant.character.escape</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8AB572</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Invalid</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#FB4938</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string />
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F8F8F0</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Invalid deprecated</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid.deprecated</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#FD971F</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F8F8F0</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Operator</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword.operator, keyword.operator.logical, meta.property-name, meta.brace, punctuation.definition.parameters.begin, punctuation.definition.parameters.end, keyword.other.parenthesis</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#CAB990</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Special operator</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword.operator.ternary</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#7BA093</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Separator</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.separator.parameter</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#EAD4AF</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Module</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword.operator.module</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FB4938</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>SublimeLinter Error</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>sublimelinter.mark.error</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#D02000</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>SublimeLinter Warning</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>sublimelinter.mark.warning</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#DDB700</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>SublimeLinter Gutter Mark</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>sublimelinter.gutter-mark</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FFFFFF</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Diff inserted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.inserted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#70c060</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Diff changed</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.changed</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#DDB700</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Diff deleted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.deleted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FB4938</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>D8D5E82E-3D5B-46B5-B38E-8C841C21347D</string>
|
||||||
|
<key>colorSpaceName</key>
|
||||||
|
<string>sRGB</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
Loading…
Reference in New Issue
Block a user