Also add a Site::render_section methodindex-subcmd
@@ -58,6 +58,10 @@ impl Config { | |||||
set_default!(config.language_code, "en".to_string()); | set_default!(config.language_code, "en".to_string()); | ||||
set_default!(config.highlight_code, false); | set_default!(config.highlight_code, false); | ||||
set_default!(config.generate_rss, false); | |||||
set_default!(config.generate_tags_pages, false); | |||||
set_default!(config.generate_categories_pages, false); | |||||
set_default!(config.insert_anchor_links, false); | |||||
match config.highlight_theme { | match config.highlight_theme { | ||||
Some(ref t) => { | Some(ref t) => { | ||||
@@ -68,11 +72,6 @@ impl Config { | |||||
None => config.highlight_theme = Some("base16-ocean-dark".to_string()) | None => config.highlight_theme = Some("base16-ocean-dark".to_string()) | ||||
}; | }; | ||||
set_default!(config.generate_rss, false); | |||||
set_default!(config.generate_tags_pages, true); | |||||
set_default!(config.generate_categories_pages, true); | |||||
set_default!(config.insert_anchor_links, false); | |||||
Ok(config) | Ok(config) | ||||
} | } | ||||
@@ -158,6 +157,7 @@ base_url = "https://replace-this-with-your-url.com" | |||||
#[test] | #[test] | ||||
fn test_errors_when_missing_required_field() { | fn test_errors_when_missing_required_field() { | ||||
// base_url is required | |||||
let config = r#" | let config = r#" | ||||
title = "" | title = "" | ||||
"#; | "#; | ||||
@@ -181,15 +181,4 @@ hello = "world" | |||||
assert_eq!(config.unwrap().extra.unwrap().get("hello").unwrap().as_str().unwrap(), "world"); | assert_eq!(config.unwrap().extra.unwrap().get("hello").unwrap().as_str().unwrap(), "world"); | ||||
} | } | ||||
#[test] | |||||
fn test_language_defaults_to_en() { | |||||
let config = r#" | |||||
title = "My site" | |||||
base_url = "https://replace-this-with-your-url.com""#; | |||||
let config = Config::parse(config); | |||||
assert!(config.is_ok()); | |||||
let config = config.unwrap(); | |||||
assert_eq!(config.language_code.unwrap(), "en"); | |||||
} | |||||
} | } |
@@ -69,6 +69,7 @@ impl Section { | |||||
section.path = section.components.join("/"); | section.path = section.components.join("/"); | ||||
section.permalink = config.make_permalink(§ion.path); | section.permalink = config.make_permalink(§ion.path); | ||||
if section.components.is_empty() { | if section.components.is_empty() { | ||||
// the index one | |||||
section.relative_path = "_index.md".to_string(); | section.relative_path = "_index.md".to_string(); | ||||
} else { | } else { | ||||
section.relative_path = format!("{}/_index.md", section.components.join("/")); | section.relative_path = format!("{}/_index.md", section.components.join("/")); | ||||
@@ -105,7 +106,7 @@ impl Section { | |||||
} | } | ||||
/// Renders the page using the default layout, unless specified in front-matter | /// Renders the page using the default layout, unless specified in front-matter | ||||
pub fn render_html(&self, sections: &HashMap<String, Section>, tera: &Tera, config: &Config) -> Result<String> { | |||||
pub fn render_html(&self, sections: HashMap<String, Section>, tera: &Tera, config: &Config) -> Result<String> { | |||||
let tpl_name = self.get_template_name(); | let tpl_name = self.get_template_name(); | ||||
let mut context = Context::new(); | let mut context = Context::new(); | ||||
@@ -114,7 +115,7 @@ impl Section { | |||||
context.add("current_url", &self.permalink); | context.add("current_url", &self.permalink); | ||||
context.add("current_path", &self.path); | context.add("current_path", &self.path); | ||||
if self.is_index() { | if self.is_index() { | ||||
context.add("sections", sections); | |||||
context.add("sections", §ions); | |||||
} | } | ||||
tera.render(&tpl_name, &context) | tera.render(&tpl_name, &context) | ||||
@@ -126,6 +127,7 @@ impl Section { | |||||
self.components.is_empty() | self.components.is_empty() | ||||
} | } | ||||
/// Returns all the paths for the pages belonging to that section | |||||
pub fn all_pages_path(&self) -> Vec<PathBuf> { | pub fn all_pages_path(&self) -> Vec<PathBuf> { | ||||
let mut paths = vec![]; | let mut paths = vec![]; | ||||
paths.extend(self.pages.iter().map(|p| p.file_path.clone())); | paths.extend(self.pages.iter().map(|p| p.file_path.clone())); | ||||
@@ -161,8 +161,6 @@ impl Site { | |||||
let base_path = self.base_path.to_string_lossy().replace("\\", "/"); | let base_path = self.base_path.to_string_lossy().replace("\\", "/"); | ||||
let content_glob = format!("{}/{}", base_path, "content/**/*.md"); | let content_glob = format!("{}/{}", base_path, "content/**/*.md"); | ||||
// TODO: make that parallel, that's the main bottleneck | |||||
// `add_section` and `add_page` can't be used in the parallel version afaik | |||||
for entry in glob(&content_glob).unwrap().filter_map(|e| e.ok()) { | for entry in glob(&content_glob).unwrap().filter_map(|e| e.ok()) { | ||||
let path = entry.as_path(); | let path = entry.as_path(); | ||||
if path.file_name().unwrap() == "_index.md" { | if path.file_name().unwrap() == "_index.md" { | ||||
@@ -611,44 +609,56 @@ impl Site { | |||||
Ok(()) | Ok(()) | ||||
} | } | ||||
fn render_sections(&self) -> Result<()> { | |||||
self.ensure_public_directory_exists()?; | |||||
let public = self.output_path.clone(); | |||||
let sections: HashMap<String, Section> = self.sections | |||||
/// Create a hashmap of paths to section | |||||
/// For example `content/posts/_index.md` key will be `posts` | |||||
fn get_sections_map(&self) -> HashMap<String, Section> { | |||||
self.sections | |||||
.values() | .values() | ||||
.map(|s| (s.components.join("/"), s.clone())) | .map(|s| (s.components.join("/"), s.clone())) | ||||
.collect(); | |||||
.collect() | |||||
} | |||||
for section in self.sections.values() { | |||||
let mut output_path = public.to_path_buf(); | |||||
for component in §ion.components { | |||||
output_path.push(component); | |||||
/// Renders a single section | |||||
fn render_section(&self, section: &Section) -> Result<()> { | |||||
self.ensure_public_directory_exists()?; | |||||
let public = self.output_path.clone(); | |||||
if !output_path.exists() { | |||||
create_directory(&output_path)?; | |||||
} | |||||
} | |||||
let mut output_path = public.to_path_buf(); | |||||
for component in §ion.components { | |||||
output_path.push(component); | |||||
for page in §ion.pages { | |||||
self.render_page(page)?; | |||||
if !output_path.exists() { | |||||
create_directory(&output_path)?; | |||||
} | } | ||||
} | |||||
if !section.meta.should_render() { | |||||
continue; | |||||
} | |||||
for page in §ion.pages { | |||||
self.render_page(page)?; | |||||
} | |||||
if section.meta.is_paginated() { | |||||
self.render_paginated(&output_path, section)?; | |||||
} else { | |||||
let output = section.render_html( | |||||
§ions, | |||||
&self.tera, | |||||
&self.config, | |||||
)?; | |||||
create_file(output_path.join("index.html"), &self.inject_livereload(output))?; | |||||
} | |||||
if !section.meta.should_render() { | |||||
return Ok(()); | |||||
} | } | ||||
if section.meta.is_paginated() { | |||||
self.render_paginated(&output_path, section)?; | |||||
} else { | |||||
let output = section.render_html( | |||||
if section.is_index() { self.get_sections_map() } else { HashMap::new() }, | |||||
&self.tera, | |||||
&self.config, | |||||
)?; | |||||
create_file(output_path.join("index.html"), &self.inject_livereload(output))?; | |||||
} | |||||
Ok(()) | |||||
} | |||||
/// Renders all sections | |||||
fn render_sections(&self) -> Result<()> { | |||||
for section in self.sections.values() { | |||||
self.render_section(section)?; | |||||
} | |||||
Ok(()) | Ok(()) | ||||
} | } | ||||
@@ -35,7 +35,7 @@ pub fn read_file<P: AsRef<Path>>(path: P) -> Result<String> { | |||||
} | } | ||||
/// Takes a full path to a .md and returns only the components after the `content` directory | |||||
/// Takes a full path to a .md and returns only the components after the first `content` directory | |||||
/// Will not return the filename as last component | /// Will not return the filename as last component | ||||
pub fn find_content_components<P: AsRef<Path>>(path: P) -> Vec<String> { | pub fn find_content_components<P: AsRef<Path>>(path: P) -> Vec<String> { | ||||
let path = path.as_ref(); | let path = path.as_ref(); | ||||
@@ -173,6 +173,7 @@ fn test_can_build_site_with_categories() { | |||||
let mut path = env::current_dir().unwrap().to_path_buf(); | let mut path = env::current_dir().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.load().unwrap(); | site.load().unwrap(); | ||||
for (i, page) in site.pages.values_mut().enumerate() { | for (i, page) in site.pages.values_mut().enumerate() { | ||||
@@ -224,6 +225,7 @@ fn test_can_build_site_with_tags() { | |||||
let mut path = env::current_dir().unwrap().to_path_buf(); | let mut path = env::current_dir().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.load().unwrap(); | site.load().unwrap(); | ||||
for (i, page) in site.pages.values_mut().enumerate() { | for (i, page) in site.pages.values_mut().enumerate() { | ||||