TIL about serde default
This commit is contained in:
parent
bb5cdc0b6c
commit
b3b2527c5d
|
@ -24,7 +24,12 @@ mod theme;
|
||||||
|
|
||||||
use theme::Theme;
|
use theme::Theme;
|
||||||
|
|
||||||
|
// We want a default base url for tests
|
||||||
|
static DEFAULT_BASE_URL: &'static str = "http://a-website.com";
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// Base URL of the site, the only required config argument
|
/// Base URL of the site, the only required config argument
|
||||||
pub base_url: String,
|
pub base_url: String,
|
||||||
|
@ -33,48 +38,47 @@ pub struct Config {
|
||||||
pub theme: Option<String>,
|
pub theme: Option<String>,
|
||||||
/// Title of the site. Defaults to None
|
/// Title of the site. Defaults to None
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
/// Whether to highlight all code blocks found in markdown files. Defaults to false
|
|
||||||
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"
|
||||||
pub default_language: Option<String>,
|
pub default_language: String,
|
||||||
|
/// Languages list and translated strings
|
||||||
|
pub translations: HashMap<String, Toml>,
|
||||||
|
|
||||||
|
/// Whether to highlight all code blocks found in markdown files. Defaults to false
|
||||||
|
pub highlight_code: bool,
|
||||||
|
/// Which themes to use for code highlighting. See Readme for supported themes
|
||||||
|
/// Defaults to "base16-ocean-dark"
|
||||||
|
pub highlight_theme: String,
|
||||||
|
|
||||||
/// Whether to generate RSS. Defaults to false
|
/// Whether to generate RSS. Defaults to false
|
||||||
pub generate_rss: Option<bool>,
|
pub generate_rss: bool,
|
||||||
/// The number of articles to include in the RSS feed. Defaults to unlimited
|
/// The number of articles to include in the RSS feed. Defaults to 10_000
|
||||||
pub rss_limit: Option<usize>,
|
pub rss_limit: usize,
|
||||||
/// Whether to generate tags and individual tag pages if some pages have them. Defaults to true
|
/// Whether to generate tags and individual tag pages if some pages have them. Defaults to true
|
||||||
pub generate_tags_pages: Option<bool>,
|
pub generate_tags_pages: bool,
|
||||||
/// Whether to generate categories and individual tag categories if some pages have them. Defaults to true
|
/// Whether to generate categories and individual tag categories if some pages have them. Defaults to true
|
||||||
pub generate_categories_pages: Option<bool>,
|
pub generate_categories_pages: bool,
|
||||||
|
|
||||||
/// Whether to compile the `sass` directory and output the css files into the static folder
|
/// Whether to compile the `sass` directory and output the css files into the static folder
|
||||||
pub compile_sass: Option<bool>,
|
pub compile_sass: bool,
|
||||||
|
/// Whether to build the search index for the content
|
||||||
|
pub build_search_index: bool,
|
||||||
/// A list of file glob patterns to ignore when processing the content folder. Defaults to none.
|
/// A list of file glob patterns to ignore when processing the content folder. Defaults to none.
|
||||||
/// Had to remove the PartialEq derive because GlobSet does not implement it. No impact
|
/// Had to remove the PartialEq derive because GlobSet does not implement it. No impact
|
||||||
/// because it's unused anyway (who wants to sort Configs?).
|
/// because it's unused anyway (who wants to sort Configs?).
|
||||||
pub ignored_content: Option<Vec<String>>,
|
pub ignored_content: Vec<String>,
|
||||||
#[serde(skip_serializing, skip_deserializing)] // not a typo, 2 are needed
|
#[serde(skip_serializing, skip_deserializing)] // not a typo, 2 are needed
|
||||||
pub ignored_content_globber: Option<GlobSet>,
|
pub ignored_content_globset: Option<GlobSet>,
|
||||||
|
|
||||||
/// Languages list and translated strings
|
|
||||||
pub translations: Option<HashMap<String, Toml>>,
|
|
||||||
|
|
||||||
/// All user params set in [extra] in the config
|
/// All user params set in [extra] in the config
|
||||||
pub extra: Option<HashMap<String, Toml>>,
|
pub extra: HashMap<String, Toml>,
|
||||||
|
|
||||||
/// Set automatically when instantiating the config. Used for cachebusting
|
/// Set automatically when instantiating the config. Used for cachebusting
|
||||||
pub build_timestamp: Option<i64>,
|
pub build_timestamp: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! set_default {
|
|
||||||
($key: expr, $default: expr) => {
|
|
||||||
if $key.is_none() {
|
|
||||||
$key = Some($default);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// Parses a string containing TOML to our Config struct
|
/// Parses a string containing TOML to our Config struct
|
||||||
|
@ -85,45 +89,33 @@ impl Config {
|
||||||
Err(e) => bail!(e)
|
Err(e) => bail!(e)
|
||||||
};
|
};
|
||||||
|
|
||||||
set_default!(config.default_language, "en".to_string());
|
if config.base_url.is_empty() || config.base_url == DEFAULT_BASE_URL {
|
||||||
set_default!(config.highlight_code, false);
|
bail!("A base URL is required in config.toml with key `base_url`");
|
||||||
set_default!(config.generate_rss, false);
|
}
|
||||||
set_default!(config.rss_limit, 20);
|
|
||||||
set_default!(config.generate_tags_pages, false);
|
|
||||||
set_default!(config.generate_categories_pages, false);
|
|
||||||
set_default!(config.compile_sass, false);
|
|
||||||
set_default!(config.ignored_content, Vec::new());
|
|
||||||
set_default!(config.translations, HashMap::new());
|
|
||||||
set_default!(config.extra, HashMap::new());
|
|
||||||
|
|
||||||
match config.highlight_theme {
|
if !THEME_SET.themes.contains_key(&config.highlight_theme) {
|
||||||
Some(ref t) => {
|
bail!("Highlight theme {} not available", config.highlight_theme)
|
||||||
if !THEME_SET.themes.contains_key(t) {
|
|
||||||
bail!("Theme {} not available", t)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None => config.highlight_theme = Some("base16-ocean-dark".to_string())
|
|
||||||
};
|
|
||||||
|
|
||||||
config.build_timestamp = Some(Utc::now().timestamp());
|
config.build_timestamp = Some(Utc::now().timestamp());
|
||||||
|
|
||||||
|
|
||||||
|
if !config.ignored_content.is_empty() {
|
||||||
// Convert the file glob strings into a compiled glob set matcher. We want to do this once,
|
// Convert the file glob strings into a compiled glob set matcher. We want to do this once,
|
||||||
// at program initialization, rather than for every page, for example. We arrange for the
|
// at program initialization, rather than for every page, for example. We arrange for the
|
||||||
// globset matcher to always exist (even though it has to be an inside an Option at the
|
// globset matcher to always exist (even though it has to be an inside an Option at the
|
||||||
// moment because of the TOML serializer); if the glob set is empty the `is_match` function
|
// moment because of the TOML serializer); if the glob set is empty the `is_match` function
|
||||||
// of the globber always returns false.
|
// of the globber always returns false.
|
||||||
let mut glob_set_builder = GlobSetBuilder::new();
|
let mut glob_set_builder = GlobSetBuilder::new();
|
||||||
|
for pat in &config.ignored_content {
|
||||||
if let Some(ref v) = config.ignored_content {
|
|
||||||
for pat in v {
|
|
||||||
let glob = match Glob::new(pat) {
|
let glob = match Glob::new(pat) {
|
||||||
Ok(g) => g,
|
Ok(g) => g,
|
||||||
Err(e) => bail!("Invalid ignored_content glob pattern: {}, error = {}", pat, e)
|
Err(e) => bail!("Invalid ignored_content glob pattern: {}, error = {}", pat, e)
|
||||||
};
|
};
|
||||||
glob_set_builder.add(glob);
|
glob_set_builder.add(glob);
|
||||||
}
|
}
|
||||||
|
config.ignored_content_globset = Some(glob_set_builder.build().expect("Bad ignored_content in config file."));
|
||||||
}
|
}
|
||||||
config.ignored_content_globber = Some(glob_set_builder.build().expect("Bad ignored_content in config file."));
|
|
||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
@ -161,19 +153,17 @@ impl Config {
|
||||||
|
|
||||||
/// Merges the extra data from the theme with the config extra data
|
/// Merges the extra data from the theme with the config extra data
|
||||||
fn add_theme_extra(&mut self, theme: &Theme) -> Result<()> {
|
fn add_theme_extra(&mut self, theme: &Theme) -> Result<()> {
|
||||||
if let Some(ref mut config_extra) = self.extra {
|
|
||||||
// 3 pass merging
|
// 3 pass merging
|
||||||
// 1. save config to preserve user
|
// 1. save config to preserve user
|
||||||
let original = config_extra.clone();
|
let original = self.extra.clone();
|
||||||
// 2. inject theme extra values
|
// 2. inject theme extra values
|
||||||
for (key, val) in &theme.extra {
|
for (key, val) in &theme.extra {
|
||||||
config_extra.entry(key.to_string()).or_insert_with(|| val.clone());
|
self.extra.entry(key.to_string()).or_insert_with(|| val.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. overwrite with original config
|
// 3. overwrite with original config
|
||||||
for (key, val) in &original {
|
for (key, val) in &original {
|
||||||
config_extra.entry(key.to_string()).or_insert_with(|| val.clone());
|
self.extra.entry(key.to_string()).or_insert_with(|| val.clone());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -187,27 +177,26 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exists only for testing purposes
|
|
||||||
#[doc(hidden)]
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
title: Some("".to_string()),
|
base_url: DEFAULT_BASE_URL.to_string(),
|
||||||
theme: None,
|
title: None,
|
||||||
base_url: "http://a-website.com/".to_string(),
|
|
||||||
highlight_code: Some(true),
|
|
||||||
highlight_theme: Some("base16-ocean-dark".to_string()),
|
|
||||||
description: None,
|
description: None,
|
||||||
default_language: Some("en".to_string()),
|
theme: None,
|
||||||
generate_rss: Some(false),
|
highlight_code: true,
|
||||||
rss_limit: Some(10_000),
|
highlight_theme: "base16-ocean-dark".to_string(),
|
||||||
generate_tags_pages: Some(true),
|
default_language: "en".to_string(),
|
||||||
generate_categories_pages: Some(true),
|
generate_rss: false,
|
||||||
compile_sass: Some(false),
|
rss_limit: 10_000,
|
||||||
ignored_content: Some(Vec::new()),
|
generate_tags_pages: true,
|
||||||
ignored_content_globber: Some(GlobSetBuilder::new().build().unwrap()),
|
generate_categories_pages: true,
|
||||||
translations: None,
|
compile_sass: false,
|
||||||
extra: None,
|
build_search_index: false,
|
||||||
|
ignored_content: Vec::new(),
|
||||||
|
ignored_content_globset: None,
|
||||||
|
translations: HashMap::new(),
|
||||||
|
extra: HashMap::new(),
|
||||||
build_timestamp: Some(1),
|
build_timestamp: Some(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +266,7 @@ hello = "world"
|
||||||
|
|
||||||
let config = Config::parse(config);
|
let config = Config::parse(config);
|
||||||
assert!(config.is_ok());
|
assert!(config.is_ok());
|
||||||
assert_eq!(config.unwrap().extra.unwrap().get("hello").unwrap().as_str().unwrap(), "world");
|
assert_eq!(config.unwrap().extra.get("hello").unwrap().as_str().unwrap(), "world");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -333,7 +322,7 @@ a_value = 10
|
||||||
"#;
|
"#;
|
||||||
let theme = Theme::parse(theme_str).unwrap();
|
let theme = Theme::parse(theme_str).unwrap();
|
||||||
assert!(config.add_theme_extra(&theme).is_ok());
|
assert!(config.add_theme_extra(&theme).is_ok());
|
||||||
let extra = config.extra.unwrap();
|
let extra = config.extra;
|
||||||
assert_eq!(extra["hello"].as_str().unwrap(), "world".to_string());
|
assert_eq!(extra["hello"].as_str().unwrap(), "world".to_string());
|
||||||
assert_eq!(extra["a_value"].as_integer().unwrap(), 10);
|
assert_eq!(extra["a_value"].as_integer().unwrap(), 10);
|
||||||
}
|
}
|
||||||
|
@ -355,26 +344,26 @@ title = "A title"
|
||||||
|
|
||||||
let config = Config::parse(config);
|
let config = Config::parse(config);
|
||||||
assert!(config.is_ok());
|
assert!(config.is_ok());
|
||||||
let translations = config.unwrap().translations.unwrap();
|
let translations = config.unwrap().translations;
|
||||||
assert_eq!(translations["fr"]["title"].as_str().unwrap(), "Un titre");
|
assert_eq!(translations["fr"]["title"].as_str().unwrap(), "Un titre");
|
||||||
assert_eq!(translations["en"]["title"].as_str().unwrap(), "A title");
|
assert_eq!(translations["en"]["title"].as_str().unwrap(), "A title");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn missing_ignored_content_results_in_empty_vector_and_empty_globber() {
|
fn missing_ignored_content_results_in_empty_vector_and_empty_globset() {
|
||||||
let config_str = r#"
|
let config_str = r#"
|
||||||
title = "My site"
|
title = "My site"
|
||||||
base_url = "example.com"
|
base_url = "example.com"
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let config = Config::parse(config_str).unwrap();
|
let config = Config::parse(config_str).unwrap();
|
||||||
let v = config.ignored_content.unwrap();
|
let v = config.ignored_content;
|
||||||
assert_eq!(v.len(), 0);
|
assert_eq!(v.len(), 0);
|
||||||
assert!(config.ignored_content_globber.unwrap().is_empty());
|
assert!(config.ignored_content_globset.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_ignored_content_results_in_empty_vector_and_empty_globber() {
|
fn empty_ignored_content_results_in_empty_vector_and_empty_globset() {
|
||||||
let config_str = r#"
|
let config_str = r#"
|
||||||
title = "My site"
|
title = "My site"
|
||||||
base_url = "example.com"
|
base_url = "example.com"
|
||||||
|
@ -382,12 +371,12 @@ ignored_content = []
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let config = Config::parse(config_str).unwrap();
|
let config = Config::parse(config_str).unwrap();
|
||||||
assert_eq!(config.ignored_content.unwrap().len(), 0);
|
assert_eq!(config.ignored_content.len(), 0);
|
||||||
assert!(config.ignored_content_globber.unwrap().is_empty());
|
assert!(config.ignored_content_globset.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn non_empty_ignored_content_results_in_vector_of_patterns_and_configured_globber() {
|
fn non_empty_ignored_content_results_in_vector_of_patterns_and_configured_globset() {
|
||||||
let config_str = r#"
|
let config_str = r#"
|
||||||
title = "My site"
|
title = "My site"
|
||||||
base_url = "example.com"
|
base_url = "example.com"
|
||||||
|
@ -395,10 +384,10 @@ ignored_content = ["*.{graphml,iso}", "*.py?"]
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let config = Config::parse(config_str).unwrap();
|
let config = Config::parse(config_str).unwrap();
|
||||||
let v = config.ignored_content.unwrap();
|
let v = config.ignored_content;
|
||||||
assert_eq!(v, vec!["*.{graphml,iso}", "*.py?"]);
|
assert_eq!(v, vec!["*.{graphml,iso}", "*.py?"]);
|
||||||
|
|
||||||
let g = config.ignored_content_globber.unwrap();
|
let g = config.ignored_content_globset.unwrap();
|
||||||
assert_eq!(g.len(), 2);
|
assert_eq!(g.len(), 2);
|
||||||
assert!(g.is_match("foo.graphml"));
|
assert!(g.is_match("foo.graphml"));
|
||||||
assert!(g.is_match("foo.iso"));
|
assert!(g.is_match("foo.iso"));
|
||||||
|
|
|
@ -130,6 +130,10 @@ impl Page {
|
||||||
let mut page = Page::parse(path, &content, config)?;
|
let mut page = Page::parse(path, &content, config)?;
|
||||||
|
|
||||||
if page.file.name == "index" {
|
if page.file.name == "index" {
|
||||||
|
let parent_dir = path.parent().unwrap();
|
||||||
|
let assets = find_related_assets(parent_dir);
|
||||||
|
|
||||||
|
if let Some(ref globset) = config.ignored_content_globset {
|
||||||
// `find_related_assets` only scans the immediate directory (it is not recursive) so our
|
// `find_related_assets` only scans the immediate directory (it is not recursive) so our
|
||||||
// filtering only needs to work against the file_name component, not the full suffix. If
|
// filtering only needs to work against the file_name component, not the full suffix. If
|
||||||
// `find_related_assets` was changed to also return files in subdirectories, we could
|
// `find_related_assets` was changed to also return files in subdirectories, we could
|
||||||
|
@ -137,16 +141,16 @@ impl Page {
|
||||||
// against the remaining path. Note that the current behaviour effectively means that
|
// against the remaining path. Note that the current behaviour effectively means that
|
||||||
// the `ignored_content` setting in the config file is limited to single-file glob
|
// the `ignored_content` setting in the config file is limited to single-file glob
|
||||||
// patterns (no "**" patterns).
|
// patterns (no "**" patterns).
|
||||||
let globber = config.ignored_content_globber.as_ref().unwrap();
|
page.assets = assets.into_iter()
|
||||||
let parent_dir = path.parent().unwrap();
|
|
||||||
page.assets = find_related_assets(parent_dir).into_iter()
|
|
||||||
.filter(|path|
|
.filter(|path|
|
||||||
match path.file_name() {
|
match path.file_name() {
|
||||||
None => true,
|
None => true,
|
||||||
Some(file) => !globber.is_match(file)
|
Some(file) => !globset.is_match(file)
|
||||||
}
|
}
|
||||||
).collect();
|
).collect();
|
||||||
|
} else {
|
||||||
|
page.assets = assets;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
page.assets = vec![];
|
page.assets = vec![];
|
||||||
}
|
}
|
||||||
|
@ -160,8 +164,8 @@ impl Page {
|
||||||
pub fn render_markdown(&mut self, permalinks: &HashMap<String, String>, tera: &Tera, config: &Config, anchor_insert: InsertAnchor) -> Result<()> {
|
pub fn render_markdown(&mut self, permalinks: &HashMap<String, String>, tera: &Tera, config: &Config, anchor_insert: InsertAnchor) -> Result<()> {
|
||||||
let context = Context::new(
|
let context = Context::new(
|
||||||
tera,
|
tera,
|
||||||
config.highlight_code.unwrap(),
|
config.highlight_code,
|
||||||
config.highlight_theme.clone().unwrap(),
|
config.highlight_theme.clone(),
|
||||||
&self.permalink,
|
&self.permalink,
|
||||||
permalinks,
|
permalinks,
|
||||||
anchor_insert
|
anchor_insert
|
||||||
|
@ -450,7 +454,7 @@ Hello world
|
||||||
let mut gsb = GlobSetBuilder::new();
|
let mut gsb = GlobSetBuilder::new();
|
||||||
gsb.add(Glob::new("*.{js,png}").unwrap());
|
gsb.add(Glob::new("*.{js,png}").unwrap());
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config.ignored_content_globber = Some(gsb.build().unwrap());
|
config.ignored_content_globset = Some(gsb.build().unwrap());
|
||||||
|
|
||||||
let res = Page::from_file(
|
let res = Page::from_file(
|
||||||
nested_path.join("index.md").as_path(),
|
nested_path.join("index.md").as_path(),
|
||||||
|
|
|
@ -100,8 +100,8 @@ impl Section {
|
||||||
pub fn render_markdown(&mut self, permalinks: &HashMap<String, String>, tera: &Tera, config: &Config) -> Result<()> {
|
pub fn render_markdown(&mut self, permalinks: &HashMap<String, String>, tera: &Tera, config: &Config) -> Result<()> {
|
||||||
let context = Context::new(
|
let context = Context::new(
|
||||||
tera,
|
tera,
|
||||||
config.highlight_code.unwrap(),
|
config.highlight_code,
|
||||||
config.highlight_theme.clone().unwrap(),
|
config.highlight_theme.clone(),
|
||||||
&self.permalink,
|
&self.permalink,
|
||||||
permalinks,
|
permalinks,
|
||||||
self.meta.insert_anchor_links.unwrap()
|
self.meta.insert_anchor_links.unwrap()
|
||||||
|
|
|
@ -376,8 +376,8 @@ impl Site {
|
||||||
|
|
||||||
/// Find all the tags and categories if it's asked in the config
|
/// Find all the tags and categories if it's asked in the config
|
||||||
pub fn populate_tags_and_categories(&mut self) {
|
pub fn populate_tags_and_categories(&mut self) {
|
||||||
let generate_tags_pages = self.config.generate_tags_pages.unwrap();
|
let generate_tags_pages = self.config.generate_tags_pages;
|
||||||
let generate_categories_pages = self.config.generate_categories_pages.unwrap();
|
let generate_categories_pages = self.config.generate_categories_pages;
|
||||||
if !generate_tags_pages && !generate_categories_pages {
|
if !generate_tags_pages && !generate_categories_pages {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -505,7 +505,7 @@ impl Site {
|
||||||
self.render_sections()?;
|
self.render_sections()?;
|
||||||
self.render_orphan_pages()?;
|
self.render_orphan_pages()?;
|
||||||
self.render_sitemap()?;
|
self.render_sitemap()?;
|
||||||
if self.config.generate_rss.unwrap() {
|
if self.config.generate_rss {
|
||||||
self.render_rss_feed()?;
|
self.render_rss_feed()?;
|
||||||
}
|
}
|
||||||
self.render_robots()?;
|
self.render_robots()?;
|
||||||
|
@ -521,7 +521,7 @@ impl Site {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.config.compile_sass.unwrap() {
|
if self.config.compile_sass {
|
||||||
self.compile_sass(&self.base_path)?;
|
self.compile_sass(&self.base_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,7 +703,7 @@ impl Site {
|
||||||
let (sorted_pages, _) = sort_pages(pages, SortBy::Date);
|
let (sorted_pages, _) = sort_pages(pages, SortBy::Date);
|
||||||
context.add("last_build_date", &sorted_pages[0].meta.date.clone().map(|d| d.to_string()));
|
context.add("last_build_date", &sorted_pages[0].meta.date.clone().map(|d| d.to_string()));
|
||||||
// limit to the last n elements)
|
// limit to the last n elements)
|
||||||
context.add("pages", &sorted_pages.iter().take(self.config.rss_limit.unwrap()).collect::<Vec<_>>());
|
context.add("pages", &sorted_pages.iter().take(self.config.rss_limit).collect::<Vec<_>>());
|
||||||
context.add("config", &self.config);
|
context.add("config", &self.config);
|
||||||
|
|
||||||
let rss_feed_url = if self.config.base_url.ends_with('/') {
|
let rss_feed_url = if self.config.base_url.ends_with('/') {
|
||||||
|
|
|
@ -193,7 +193,7 @@ fn can_build_site_with_categories() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
||||||
path.push("test_site");
|
path.push("test_site");
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
let mut site = Site::new(&path, "config.toml").unwrap();
|
||||||
site.config.generate_categories_pages = Some(true);
|
site.config.generate_categories_pages = true;
|
||||||
site.load().unwrap();
|
site.load().unwrap();
|
||||||
|
|
||||||
for (i, page) in site.pages.values_mut().enumerate() {
|
for (i, page) in site.pages.values_mut().enumerate() {
|
||||||
|
@ -247,7 +247,7 @@ fn can_build_site_with_tags() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
||||||
path.push("test_site");
|
path.push("test_site");
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
let mut site = Site::new(&path, "config.toml").unwrap();
|
||||||
site.config.generate_tags_pages = Some(true);
|
site.config.generate_tags_pages = true;
|
||||||
site.load().unwrap();
|
site.load().unwrap();
|
||||||
|
|
||||||
for (i, page) in site.pages.values_mut().enumerate() {
|
for (i, page) in site.pages.values_mut().enumerate() {
|
||||||
|
|
|
@ -23,8 +23,8 @@ macro_rules! required_string_arg {
|
||||||
|
|
||||||
|
|
||||||
pub fn make_trans(config: Config) -> GlobalFn {
|
pub fn make_trans(config: Config) -> GlobalFn {
|
||||||
let translations_config = config.translations.unwrap();
|
let translations_config = config.translations;
|
||||||
let default_lang = to_value(config.default_language.unwrap()).unwrap();
|
let default_lang = to_value(config.default_language).unwrap();
|
||||||
|
|
||||||
Box::new(move |args| -> Result<Value> {
|
Box::new(move |args| -> Result<Value> {
|
||||||
let key = required_string_arg!(args.get("key"), "`trans` requires a `key` argument.");
|
let key = required_string_arg!(args.get("key"), "`trans` requires a `key` argument.");
|
||||||
|
|
|
@ -19,6 +19,9 @@ compile_sass = %COMPILE_SASS%
|
||||||
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Gutenberg
|
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Gutenberg
|
||||||
highlight_code = %HIGHLIGHT%
|
highlight_code = %HIGHLIGHT%
|
||||||
|
|
||||||
|
# Whether to build a search index to be used later on by a JavaScript library
|
||||||
|
build_search_index = %SEARCH%
|
||||||
|
|
||||||
[extra]
|
[extra]
|
||||||
# Put all your custom variables here
|
# Put all your custom variables here
|
||||||
"#;
|
"#;
|
||||||
|
@ -37,11 +40,13 @@ pub fn create_new_project(name: &str) -> Result<()> {
|
||||||
let base_url = ask_url("> What is the URL of your site?", "https://example.com")?;
|
let base_url = ask_url("> What is the URL of your site?", "https://example.com")?;
|
||||||
let compile_sass = ask_bool("> Do you want to enable Sass compilation?", true)?;
|
let compile_sass = ask_bool("> Do you want to enable Sass compilation?", true)?;
|
||||||
let highlight = ask_bool("> Do you want to enable syntax highlighting?", false)?;
|
let highlight = ask_bool("> Do you want to enable syntax highlighting?", false)?;
|
||||||
|
let search = ask_bool("> Do you want to build a search index of the content?", false)?;
|
||||||
|
|
||||||
let config = CONFIG
|
let config = CONFIG
|
||||||
.trim_left()
|
.trim_left()
|
||||||
.replace("%BASE_URL%", &base_url)
|
.replace("%BASE_URL%", &base_url)
|
||||||
.replace("%COMPILE_SASS%", &format!("{}", compile_sass))
|
.replace("%COMPILE_SASS%", &format!("{}", compile_sass))
|
||||||
|
.replace("%SEARCH%", &format!("{}", search))
|
||||||
.replace("%HIGHLIGHT%", &format!("{}", highlight));
|
.replace("%HIGHLIGHT%", &format!("{}", highlight));
|
||||||
|
|
||||||
create_file(&path.join("config.toml"), &config)?;
|
create_file(&path.join("config.toml"), &config)?;
|
||||||
|
@ -53,6 +58,7 @@ pub fn create_new_project(name: &str) -> Result<()> {
|
||||||
if compile_sass {
|
if compile_sass {
|
||||||
create_dir(path.join("sass"))?;
|
create_dir(path.join("sass"))?;
|
||||||
}
|
}
|
||||||
|
// TODO: if search == true, copy a lunr js file embedded in gutenberg
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
console::success(&format!("Done! Your site was created in {:?}", canonicalize(path).unwrap()));
|
console::success(&format!("Done! Your site was created in {:?}", canonicalize(path).unwrap()));
|
||||||
|
|
|
@ -163,7 +163,7 @@ pub fn serve(interface: &str, port: &str, output_dir: &str, base_url: &str, conf
|
||||||
if watching_static {
|
if watching_static {
|
||||||
watchers.push("static");
|
watchers.push("static");
|
||||||
}
|
}
|
||||||
if site.config.compile_sass.unwrap() {
|
if site.config.compile_sass {
|
||||||
watchers.push("sass");
|
watchers.push("sass");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue