From 6843ec5c9c3a80fc8173ac0c53af8d73cf6cdbbc Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Sat, 6 Oct 2018 13:37:06 +0200 Subject: [PATCH] Rebuild more things now that it is more performant to do so Fix #122 --- components/library/src/content/section.rs | 11 ---- components/library/src/library.rs | 25 +++++--- components/library/src/taxonomies/mod.rs | 1 + components/rebuild/src/lib.rs | 61 +++++-------------- components/site/src/lib.rs | 6 -- docs/content/documentation/content/section.md | 36 +++++------ 6 files changed, 49 insertions(+), 91 deletions(-) diff --git a/components/library/src/content/section.rs b/components/library/src/content/section.rs index 63a59c41..de4df12d 100644 --- a/components/library/src/content/section.rs +++ b/components/library/src/content/section.rs @@ -244,17 +244,6 @@ impl Section { self.file.components.is_empty() } - /// Returns all the paths of the pages belonging to that section - pub fn all_pages_path(&self) -> Vec { - let paths = vec![]; - paths - } - - /// Whether the page given belongs to that section - pub fn is_child_page(&self, path: &PathBuf) -> bool { - false - } - /// Creates a vectors of asset URLs. fn serialize_assets(&self) -> Vec { self.assets.iter() diff --git a/components/library/src/library.rs b/components/library/src/library.rs index a204a49c..8c45f1d8 100644 --- a/components/library/src/library.rs +++ b/components/library/src/library.rs @@ -101,7 +101,8 @@ impl Library { self.sections.get_mut(*section_key).unwrap().pages.push(key); } } - self.sort_sections_pages(None); + + self.sort_sections_pages(); let sections = self.paths_to_sections.clone(); let mut sections_weight = HashMap::new(); @@ -120,17 +121,10 @@ impl Library { } } - /// Sort all sections pages unless `only` is set. - /// If `only` is set, only the pages of the section at that specific Path will be rendered. - pub fn sort_sections_pages(&mut self, only: Option<&Path>) { + /// Sort all sections pages + pub fn sort_sections_pages(&mut self) { let mut updates = HashMap::new(); for (key, section) in &self.sections { - if let Some(p) = only { - if p != section.file.path { - continue; - } - } - let (sorted_pages, cannot_be_sorted_pages) = match section.meta.sort_by { SortBy::None => continue, SortBy::Date => { @@ -214,6 +208,17 @@ impl Library { .collect() } + pub fn find_parent_section(&self, path: &Path) -> Option<&Section> { + let page_key = self.paths_to_pages[path]; + for s in self.sections.values() { + if s.pages.contains(&page_key) { + return Some(s) + } + } + + None + } + pub fn get_section(&self, path: &PathBuf) -> Option<&Section> { self.sections.get(self.paths_to_sections.get(path).cloned().unwrap_or_default()) } diff --git a/components/library/src/taxonomies/mod.rs b/components/library/src/taxonomies/mod.rs index 3b1f812b..205b3968 100644 --- a/components/library/src/taxonomies/mod.rs +++ b/components/library/src/taxonomies/mod.rs @@ -34,6 +34,7 @@ impl<'a> SerializedTaxonomyItem<'a> { slug: &item.slug, permalink: &item.permalink, pages, + } } } diff --git a/components/rebuild/src/lib.rs b/components/rebuild/src/lib.rs index fd36cd03..0ba50cb3 100644 --- a/components/rebuild/src/lib.rs +++ b/components/rebuild/src/lib.rs @@ -12,19 +12,6 @@ use library::{Page, Section}; use front_matter::{PageFrontMatter, SectionFrontMatter}; -/// Finds the section that contains the page given if there is one -pub fn find_parent_section<'a>(site: &'a Site, page: &Page) -> Option<&'a Section> { - for section in site.library.sections_values() { - // TODO: remove that, it's wrong now it should check the page key - if section.is_child_page(&page.file.path) { - return Some(section); - } - } - - None -} - - #[derive(Debug, Clone, Copy, PartialEq)] pub enum PageChangesNeeded { /// Editing `taxonomies` @@ -106,7 +93,6 @@ fn delete_element(site: &mut Site, path: &Path, is_section: bool) -> Result<()> if is_section { if let Some(s) = site.library.remove_section(&path.to_path_buf()) { site.permalinks.remove(&s.file.relative); - site.populate_sections(); } } else if let Some(p) = site.library.remove_page(&path.to_path_buf()) { site.permalinks.remove(&p.file.relative); @@ -114,15 +100,11 @@ fn delete_element(site: &mut Site, path: &Path, is_section: bool) -> Result<()> if !p.meta.taxonomies.is_empty() { site.populate_taxonomies()?; } - - // if there is a parent section, we will need to re-render it - // most likely - if find_parent_section(site, &p).is_some() { - site.populate_sections(); - } } + site.populate_sections(); // Ensure we have our fn updated so it doesn't contain the permalink(s)/section/page deleted + site.register_early_global_fns(); site.register_tera_global_fns(); // Deletion is something that doesn't happen all the time so we // don't need to optimise it too much @@ -137,9 +119,12 @@ fn handle_section_editing(site: &mut Site, path: &Path) -> Result<()> { // Updating a section Some(prev) => { // Copy the section data so we don't end up with an almost empty object - site.library.get_section_mut(&pathbuf).unwrap().pages = prev.pages; - site.library.get_section_mut(&pathbuf).unwrap().ignored_pages = prev.ignored_pages; - site.library.get_section_mut(&pathbuf).unwrap().subsections = prev.subsections; + { + let s = site.library.get_section_mut(&pathbuf).unwrap(); + s.pages = prev.pages; + s.ignored_pages = prev.ignored_pages; + s.subsections = prev.subsections; + } if site.library.get_section(&pathbuf).unwrap().meta == prev.meta { // Front matter didn't change, only content did @@ -152,7 +137,6 @@ fn handle_section_editing(site: &mut Site, path: &Path) -> Result<()> { // Sort always comes first if present so the rendering will be fine match changes { SectionChangesNeeded::Sort => { - site.sort_sections_pages(Some(path)); site.register_tera_global_fns(); } SectionChangesNeeded::Render => site.render_section(&site.library.get_section(&pathbuf).unwrap(), false)?, @@ -177,7 +161,7 @@ fn handle_section_editing(site: &mut Site, path: &Path) -> Result<()> { macro_rules! render_parent_section { ($site: expr, $path: expr) => { - if let Some(s) = find_parent_section($site, &$site.library.get_page(&$path.to_path_buf()).unwrap()) { + if let Some(s) = $site.library.find_parent_section($path) { $site.render_section(s, false)?; }; } @@ -190,6 +174,8 @@ fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> { match site.add_page(page, true)? { // Updating a page Some(prev) => { + site.populate_sections(); + // Front matter didn't change, only content did if site.library.get_page(&pathbuf).unwrap().meta == prev.meta { // Other than the page itself, the summary might be seen @@ -197,42 +183,24 @@ fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> { if site.library.get_page(&pathbuf).unwrap().summary.is_some() { render_parent_section!(site, path); } - // TODO: register_tera_global_fns is expensive as it involves lots of cloning - // I can't think of a valid usecase where you would need the content - // of a page through a global fn so it's commented out for now - // site.register_tera_global_fns(); + site.register_tera_global_fns(); return site.render_page(&site.library.get_page(&pathbuf).unwrap()); } // Front matter changed - let mut sections_populated = false; for changes in find_page_front_matter_changes(&site.library.get_page(&pathbuf).unwrap().meta, &prev.meta) { + site.register_tera_global_fns(); + // Sort always comes first if present so the rendering will be fine match changes { PageChangesNeeded::Taxonomies => { site.populate_taxonomies()?; - site.register_tera_global_fns(); site.render_taxonomies()?; } PageChangesNeeded::Sort => { - let section_path = match find_parent_section(site, &site.library.get_page(&pathbuf).unwrap()) { - Some(s) => s.file.path.clone(), - None => continue // Do nothing if it's an orphan page - }; - if !sections_populated { - site.populate_sections(); - sections_populated = true; - } - site.sort_sections_pages(Some(§ion_path)); - site.register_tera_global_fns(); site.render_index()?; } PageChangesNeeded::Render => { - if !sections_populated { - site.populate_sections(); - sections_populated = true; - } - site.register_tera_global_fns(); render_parent_section!(site, path); site.render_page(&site.library.get_page(&path.to_path_buf()).unwrap())?; } @@ -244,6 +212,7 @@ fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> { None => { site.populate_sections(); site.populate_taxonomies()?; + site.register_early_global_fns(); site.register_tera_global_fns(); // No need to optimise that yet, we can revisit if it becomes an issue site.build() diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index 69804abf..6734d9ed 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -357,12 +357,6 @@ impl Site { self.library.populate_sections(); } - /// Sorts the pages of the section at the given path - /// By default will sort all sections but can be made to only sort a single one by providing a path - pub fn sort_sections_pages(&mut self, only: Option<&Path>) { - self.library.sort_sections_pages(only); - } - /// Find all the tags and categories if it's asked in the config pub fn populate_taxonomies(&mut self) -> Result<()> { if self.config.taxonomies.is_empty() { diff --git a/docs/content/documentation/content/section.md b/docs/content/documentation/content/section.md index 74c32e0a..22fac302 100644 --- a/docs/content/documentation/content/section.md +++ b/docs/content/documentation/content/section.md @@ -3,11 +3,11 @@ title = "Section" weight = 20 +++ -A section is created whenever a folder (or subfolder) in the `content` section contains an -`_index.md` file. If a folder does not contain an `_index.md` file, no section will be +A section is created whenever a folder (or subfolder) in the `content` section contains an +`_index.md` file. If a folder does not contain an `_index.md` file, no section will be created, but markdown files within that folder will still create pages (known as orphan pages). -The index page (i.e., the page displayed when a user browses to your `base_url`) is a section, +The index page (i.e., the page displayed when a user browses to your `base_url`) is a section, which is created whether or not you add an `_index.md` file at the root of your `content` folder. If you do not create an `_index.md` file in your content directory, this main content section will not have any content or metadata. If you would like to add content or metadata, you can add an @@ -96,9 +96,9 @@ by setting the `paginate_path` variable, which defaults to `page`. ## Sorting It is very common for Gutenberg templates to iterate over pages or sections -to display all pages/sections a given directory. Consider a very simple +to display all pages/sections a given directory. Consider a very simple example: a `blog` directory with three files: `blog/Post_1.md`, -`blog/Post_2.md`, and `blog/Post_3.md`. To iterate over these posts and +`blog/Post_2.md`, and `blog/Post_3.md`. To iterate over these posts and create a list of links to the posts, a simple template might look like this: ```j2 @@ -107,15 +107,15 @@ create a list of links to the posts, a simple template might look like this: {% endfor %} ``` -This would iterate over the posts, and would do so in a specific order -based on the `sort_by` variable set in the `_index.md` page for the +This would iterate over the posts, and would do so in a specific order +based on the `sort_by` variable set in the `_index.md` page for the containing section. The `sort_by` variable can be given three values: `date`, `weight`, and `none`. If no `sort_by` method is set, the pages will be sorted in the `none` order, which is not intended to be used for sorted content. Any page that is missing the data it needs to be sorted will be ignored and -won't be rendered. For example, if a page is missing the date variable the -containing section sets `sort_by = "date"`, then that page will be ignored. +won't be rendered. For example, if a page is missing the date variable the +containing section sets `sort_by = "date"`, then that page will be ignored. The terminal will warn you if this is happening. If several pages have the same date/weight/order, their permalink will be used @@ -127,18 +127,18 @@ The `sort_by` front-matter variable can have the following values: ### `date` This will sort all pages by their `date` field, from the most recent (at the top of the list) to the oldest (at the bottom of the list). Each page will -get `page.earlier` and `page.later` variables that contain the pages with +get `page.earlier` and `page.later` variables that contain the pages with earlier and later dates, respectively. ### `weight` -This will be sort all pages by their `weight` field, from lightest weight -(at the top of the list) to heaviest (at the bottom of the list). Each -page gets `page.lighter` and `page.heavier` variables that contain the +This will be sort all pages by their `weight` field, from lightest weight +(at the top of the list) to heaviest (at the bottom of the list). Each +page gets `page.lighter` and `page.heavier` variables that contain the pages with lighter and heavier weights, respectively. -When iterating through pages, you may wish to use the Tera `reverse` filter, +When iterating through pages, you may wish to use the Tera `reverse` filter, which reverses the order of the pages. Thus, after using the `reverse` filter, -pages sorted by weight will be sorted from lightest (at the top) to heaviest +pages sorted by weight will be sorted from lightest (at the top) to heaviest (at the bottom); pages sorted by date will be sorted from oldest (at the top) to newest (at the bottom). @@ -153,8 +153,8 @@ the top of the list and the heaviest (highest `weight`) will be at the top; the `reverse` filter reverses this order. **Note**: Unlike pages, permalinks will **not** be used to break ties between -equally weighted sections. Thus, if the `weight` variable for your section is not set (or if it -is set in a way that produces ties), then your sections will be sorted in +equally weighted sections. Thus, if the `weight` variable for your section is not set (or if it +is set in a way that produces ties), then your sections will be sorted in **random** order. Moreover, that order is determined at build time and will -change with each site rebuild. Thus, if there is any chance that you will +change with each site rebuild. Thus, if there is any chance that you will iterate over your sections, you should always assign them weight.