diff --git a/README.md b/README.md index d747337d..6c4b91fc 100644 --- a/README.md +++ b/README.md @@ -123,14 +123,18 @@ which template will be used to render that section. Sections will also automatically pick up their subsections, allowing you to make some complex pages layout and table of contents. +A special case is the `_index.md` at the root of the `content` directory which represents the homepage. It is only there +to control pagination and sorting of the homepage. + ### Code highlighting themes Code highlighting can be turned on by setting `highlight_code = true` in `config.toml`. When turned on, all text between backticks will be highlighted, like the example below. - ```rust - let site = Site::new(); - ``` +```rust +let site = Site::new(); +``` + If the name of the language is not given, it will default to plain-text highlighting. Gutenberg uses Sublime Text themes for syntax highlighting. It comes with the following theme diff --git a/src/markdown.rs b/src/markdown.rs index 5ba63bbc..75b8601c 100644 --- a/src/markdown.rs +++ b/src/markdown.rs @@ -37,7 +37,7 @@ lazy_static!{ }; } -/// A ShortCode that has a body +/// A shortcode that has a body /// Called by having some content like {% ... %} body {% end %} /// We need the struct to hold the data while we're processing the markdown #[derive(Debug)] @@ -62,7 +62,7 @@ impl ShortCode { pub fn render(&self, tera: &Tera) -> Result { let mut context = Context::new(); - for (key, value) in self.args.iter() { + for (key, value) in &self.args { context.add(key, value); } context.add("body", &self.body); @@ -132,7 +132,7 @@ pub fn markdown_to_html(content: &str, permalinks: &HashMap, ter // for example an article could have several titles named Example // We add a counter after the slug if the slug is already present, which // means we will have example, example-1, example-2 etc - fn find_anchor(anchors: &Vec, name: String, level: u8) -> String { + fn find_anchor(anchors: &[String], name: String, level: u8) -> String { if level == 0 && !anchors.contains(&name) { return name.to_string(); } @@ -164,16 +164,14 @@ pub fn markdown_to_html(content: &str, permalinks: &HashMap, ter } // Shortcode without body - if shortcode_block.is_none() && text.starts_with("{{") && text.ends_with("}}") { - if SHORTCODE_RE.is_match(&text) { - let (name, args) = parse_shortcode(&text); - added_shortcode = true; - match render_simple_shortcode(tera, &name, &args) { - Ok(s) => return Event::Html(Owned(format!("

{}", s))), - Err(e) => { - error = Some(e); - return Event::Html(Owned("".to_string())); - } + if shortcode_block.is_none() && text.starts_with("{{") && text.ends_with("}}") && SHORTCODE_RE.is_match(&text) { + let (name, args) = parse_shortcode(&text); + added_shortcode = true; + match render_simple_shortcode(tera, &name, &args) { + Ok(s) => return Event::Html(Owned(format!("

{}", s))), + Err(e) => { + error = Some(e); + return Event::Html(Owned("".to_string())); } } // non-matching will be returned normally below @@ -277,7 +275,7 @@ pub fn markdown_to_html(content: &str, permalinks: &HashMap, ter }; } - return Event::Start(Tag::Link(link.clone(), title.clone())); + Event::Start(Tag::Link(link.clone(), title.clone())) }, // need to know when we are in a code block to disable shortcodes in them Event::Start(Tag::Code) => { @@ -291,7 +289,7 @@ pub fn markdown_to_html(content: &str, permalinks: &HashMap, ter Event::Start(Tag::Header(num)) => { in_header = true; // ugly eh - return Event::Html(Owned(format!(" { in_header = false; diff --git a/src/page.rs b/src/page.rs index 94bc865f..e9a0312d 100644 --- a/src/page.rs +++ b/src/page.rs @@ -152,22 +152,21 @@ impl Page { // Pages with custom urls exists outside of sections if let Some(ref u) = page.meta.url { page.path = u.trim().to_string(); - } else { - if !page.components.is_empty() { - // If we have a folder with an asset, don't consider it as a component - if page.file_name == "index" { - page.components.pop(); - // also set parent_path to grandparent instead - page.parent_path = page.parent_path.parent().unwrap().to_path_buf(); - } - - // Don't add a trailing slash to sections - page.path = format!("{}/{}", page.components.join("/"), page.slug); - } else { - page.path = page.slug.clone(); + } else if !page.components.is_empty() { + // If we have a folder with an asset, don't consider it as a component + if page.file_name == "index" { + page.components.pop(); + // also set parent_path to grandparent instead + page.parent_path = page.parent_path.parent().unwrap().to_path_buf(); } + + // Don't add a trailing slash to sections + page.path = format!("{}/{}", page.components.join("/"), page.slug); + } else { + page.path = page.slug.clone(); } + page.permalink = config.make_permalink(&page.path); Ok(page) diff --git a/src/site.rs b/src/site.rs index 74612ce3..6cd5cf68 100644 --- a/src/site.rs +++ b/src/site.rs @@ -64,6 +64,7 @@ pub struct Site { pub config: Config, pub pages: HashMap, pub sections: BTreeMap, + pub index: Option
, pub tera: Tera, live_reload: bool, output_path: PathBuf, @@ -91,6 +92,7 @@ impl Site { config: get_config(path, config_file), pages: HashMap::new(), sections: BTreeMap::new(), + index: None, tera: tera, live_reload: false, output_path: path.join("public"), @@ -117,16 +119,21 @@ impl Site { /// Reads all .md files in the `content` directory and create pages/sections /// out of them pub fn load(&mut self) -> Result<()> { - let path = self.base_path.to_string_lossy().replace("\\", "/"); - let content_glob = format!("{}/{}", path, "content/**/*.md"); + let base_path = self.base_path.to_string_lossy().replace("\\", "/"); + 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()) { let path = entry.as_path(); - if path.file_name().unwrap() == "_index.md" { - self.add_section(path)?; + // Index section + if path.parent().unwrap() == self.base_path.join("content") { + self.index = Some(Section::from_file(path, &self.config)?); + } else { + // all the other sections + self.add_section(path)?; + } } else { self.add_page(path)?; } diff --git a/test_site/content/_index.md b/test_site/content/_index.md new file mode 100644 index 00000000..a51bfdc4 --- /dev/null +++ b/test_site/content/_index.md @@ -0,0 +1,4 @@ ++++ +title = "Home" +description = "" ++++ diff --git a/tests/front_matter.rs b/tests/front_matter.rs index bea21cf5..5b5c833e 100644 --- a/tests/front_matter.rs +++ b/tests/front_matter.rs @@ -53,10 +53,10 @@ authors = ["Bob", "Alice"]"#; assert_eq!(res.title, "Hello".to_string()); assert_eq!(res.slug.unwrap(), "hello-world".to_string()); let extra = res.extra.unwrap(); - assert_eq!(extra.get("language").unwrap(), &to_value("en").unwrap()); + assert_eq!(extra["language"], to_value("en").unwrap()); assert_eq!( - extra.get("authors").unwrap(), - &to_value(["Bob".to_string(), "Alice".to_string()]).unwrap() + extra["authors"], + to_value(["Bob".to_string(), "Alice".to_string()]).unwrap() ); } diff --git a/tests/site.rs b/tests/site.rs index cd2500dc..fbdbbac0 100644 --- a/tests/site.rs +++ b/tests/site.rs @@ -22,6 +22,9 @@ fn test_can_parse_site() { assert_eq!(site.pages.len(), 10); let posts_path = path.join("content").join("posts"); + // We have an index page + assert!(site.index.is_some()); + // Make sure we remove all the pwd + content from the sections let basic = &site.pages[&posts_path.join("simple.md")]; assert_eq!(basic.components, vec!["posts".to_string()]);