You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
10.0KB

  1. use std::collections::{HashMap, HashSet};
  2. use std::path::{Path, PathBuf};
  3. use slotmap::{DenseSlotMap, Key};
  4. use front_matter::SortBy;
  5. use sorting::{find_siblings, sort_pages_by_weight, sort_pages_by_date};
  6. use content::{Page, Section};
  7. /// Houses everything about pages and sections
  8. /// Think of it as a database where each page and section has an id (Key here)
  9. /// that can be used to find the actual value
  10. /// Sections and pages can then refer to other elements by those keys, which are very cheap to
  11. /// copy.
  12. /// We can assume the keys are always existing as removing a page/section deletes all references
  13. /// to that key.
  14. #[derive(Debug)]
  15. pub struct Library {
  16. /// All the pages of the site
  17. pages: DenseSlotMap<Page>,
  18. /// All the sections of the site
  19. sections: DenseSlotMap<Section>,
  20. /// A mapping path -> key for pages so we can easily get their key
  21. paths_to_pages: HashMap<PathBuf, Key>,
  22. /// A mapping path -> key for sections so we can easily get their key
  23. paths_to_sections: HashMap<PathBuf, Key>,
  24. }
  25. impl Library {
  26. pub fn new(cap_pages: usize, cap_sections: usize) -> Self {
  27. Library {
  28. pages: DenseSlotMap::with_capacity(cap_pages),
  29. sections: DenseSlotMap::with_capacity(cap_sections),
  30. paths_to_pages: HashMap::with_capacity(cap_pages),
  31. paths_to_sections: HashMap::with_capacity(cap_sections),
  32. }
  33. }
  34. /// Add a section and return its Key
  35. pub fn insert_section(&mut self, section: Section) -> Key {
  36. let path = section.file.path.clone();
  37. let key = self.sections.insert(section);
  38. self.paths_to_sections.insert(path, key);
  39. key
  40. }
  41. /// Add a page and return its Key
  42. pub fn insert_page(&mut self, page: Page) -> Key {
  43. let path = page.file.path.clone();
  44. let key = self.pages.insert(page);
  45. self.paths_to_pages.insert(path, key);
  46. key
  47. }
  48. pub fn pages(&self) -> &DenseSlotMap<Page> {
  49. &self.pages
  50. }
  51. pub fn pages_mut(&mut self) -> &mut DenseSlotMap<Page> {
  52. &mut self.pages
  53. }
  54. pub fn pages_values(&self) -> Vec<&Page> {
  55. self.pages.values().collect::<Vec<_>>()
  56. }
  57. pub fn sections(&self) -> &DenseSlotMap<Section> {
  58. &self.sections
  59. }
  60. pub fn sections_mut(&mut self) -> &mut DenseSlotMap<Section> {
  61. &mut self.sections
  62. }
  63. pub fn sections_values(&self) -> Vec<&Section> {
  64. self.sections.values().collect::<Vec<_>>()
  65. }
  66. /// Find out the direct subsections of each subsection if there are some
  67. /// as well as the pages for each section
  68. pub fn populate_sections(&mut self) {
  69. let mut grandparent_paths: HashMap<PathBuf, Vec<_>> = HashMap::new();
  70. for section in self.sections.values_mut() {
  71. if let Some(ref grand_parent) = section.file.grand_parent {
  72. grandparent_paths
  73. .entry(grand_parent.to_path_buf())
  74. .or_insert_with(|| vec![])
  75. .push(section.file.path.clone());
  76. }
  77. // Make sure the pages of a section are empty since we can call that many times on `serve`
  78. section.pages = vec![];
  79. section.ignored_pages = vec![];
  80. }
  81. for (key, page) in &mut self.pages {
  82. let parent_section_path = page.file.parent.join("_index.md");
  83. if let Some(section_key) = self.paths_to_sections.get(&parent_section_path) {
  84. self.sections.get_mut(*section_key).unwrap().pages.push(key);
  85. page.parent_section = Some(*section_key);
  86. }
  87. }
  88. self.sort_sections_pages();
  89. let sections = self.paths_to_sections.clone();
  90. let mut sections_weight = HashMap::new();
  91. for (key, section) in &self.sections {
  92. sections_weight.insert(key, section.meta.weight);
  93. }
  94. for (grandparent, children) in &grandparent_paths {
  95. let mut subsections = vec![];
  96. let grandparent_path = grandparent.join("_index.md");
  97. if let Some(ref mut section) = self.get_section_mut(&grandparent_path) {
  98. subsections = children.iter().map(|p| sections[p]).collect();
  99. subsections.sort_by(|a, b| sections_weight[a].cmp(&sections_weight[b]));
  100. section.subsections = subsections.clone();
  101. }
  102. // Only there for subsections so we must have a parent section
  103. for key in &subsections {
  104. if let Some(ref mut subsection) = self.sections.get_mut(*key) {
  105. subsection.parent_section = Some(sections[&grandparent_path]);
  106. }
  107. }
  108. }
  109. }
  110. /// Sort all sections pages
  111. pub fn sort_sections_pages(&mut self) {
  112. let mut updates = HashMap::new();
  113. for (key, section) in &self.sections {
  114. let (sorted_pages, cannot_be_sorted_pages) = match section.meta.sort_by {
  115. SortBy::None => continue,
  116. SortBy::Date => {
  117. let data = section.pages
  118. .iter()
  119. .map(|k| {
  120. if let Some(page) = self.pages.get(*k) {
  121. (k, page.meta.datetime, page.permalink.as_ref())
  122. } else {
  123. unreachable!("Sorting got an unknown page")
  124. }
  125. })
  126. .collect();
  127. sort_pages_by_date(data)
  128. },
  129. SortBy::Weight => {
  130. let data = section.pages
  131. .iter()
  132. .map(|k| {
  133. if let Some(page) = self.pages.get(*k) {
  134. (k, page.meta.weight, page.permalink.as_ref())
  135. } else {
  136. unreachable!("Sorting got an unknown page")
  137. }
  138. })
  139. .collect();
  140. sort_pages_by_weight(data)
  141. }
  142. };
  143. updates.insert(key, (sorted_pages, cannot_be_sorted_pages, section.meta.sort_by));
  144. }
  145. for (key, (sorted, cannot_be_sorted, sort_by)) in updates {
  146. // Find sibling between sorted pages first
  147. let with_siblings = find_siblings(sorted.iter().map(|k| {
  148. if let Some(page) = self.pages.get(*k) {
  149. (k, page.is_draft())
  150. } else {
  151. unreachable!("Sorting got an unknown page")
  152. }
  153. }).collect());
  154. for (k2, val1, val2) in with_siblings {
  155. if let Some(page) = self.pages.get_mut(k2) {
  156. match sort_by {
  157. SortBy::Date => {
  158. page.earlier = val2;
  159. page.later = val1;
  160. },
  161. SortBy::Weight => {
  162. page.lighter = val1;
  163. page.heavier = val2;
  164. },
  165. SortBy::None => unreachable!("Impossible to find siblings in SortBy::None")
  166. }
  167. } else {
  168. unreachable!("Sorting got an unknown page")
  169. }
  170. }
  171. if let Some(s) = self.sections.get_mut(key) {
  172. s.pages = sorted;
  173. s.ignored_pages = cannot_be_sorted;
  174. }
  175. }
  176. }
  177. /// Find all the orphan pages: pages that are in a folder without an `_index.md`
  178. pub fn get_all_orphan_pages(&self) -> Vec<&Page> {
  179. let pages_in_sections = self.sections
  180. .values()
  181. .flat_map(|s| &s.pages)
  182. .collect::<HashSet<_>>();
  183. self.pages
  184. .iter()
  185. .filter(|(key, _)| !pages_in_sections.contains(&key))
  186. .map(|(_, page)| page)
  187. .collect()
  188. }
  189. pub fn find_parent_section(&self, path: &Path) -> Option<&Section> {
  190. let page_key = self.paths_to_pages[path];
  191. for s in self.sections.values() {
  192. if s.pages.contains(&page_key) {
  193. return Some(s)
  194. }
  195. }
  196. None
  197. }
  198. /// Only used in tests
  199. pub fn get_section_key(&self, path: &PathBuf) -> Option<&Key> {
  200. self.paths_to_sections.get(path)
  201. }
  202. pub fn get_section(&self, path: &PathBuf) -> Option<&Section> {
  203. self.sections.get(self.paths_to_sections.get(path).cloned().unwrap_or_default())
  204. }
  205. pub fn get_section_mut(&mut self, path: &PathBuf) -> Option<&mut Section> {
  206. self.sections.get_mut(self.paths_to_sections.get(path).cloned().unwrap_or_default())
  207. }
  208. pub fn get_section_by_key(&self, key: Key) -> &Section {
  209. self.sections.get(key).unwrap()
  210. }
  211. pub fn get_section_mut_by_key(&mut self, key: Key) -> &mut Section {
  212. self.sections.get_mut(key).unwrap()
  213. }
  214. pub fn get_section_path_by_key(&self, key: Key) -> &str {
  215. &self.get_section_by_key(key).file.relative
  216. }
  217. pub fn get_page(&self, path: &PathBuf) -> Option<&Page> {
  218. self.pages.get(self.paths_to_pages.get(path).cloned().unwrap_or_default())
  219. }
  220. pub fn get_page_by_key(&self, key: Key) -> &Page {
  221. self.pages.get(key).unwrap()
  222. }
  223. pub fn remove_section(&mut self, path: &PathBuf) -> Option<Section> {
  224. if let Some(k) = self.paths_to_sections.remove(path) {
  225. self.sections.remove(k)
  226. } else {
  227. None
  228. }
  229. }
  230. pub fn remove_page(&mut self, path: &PathBuf) -> Option<Page> {
  231. if let Some(k) = self.paths_to_pages.remove(path) {
  232. self.pages.remove(k)
  233. } else {
  234. None
  235. }
  236. }
  237. /// Used in rebuild, to check if we know it already
  238. pub fn contains_section(&self, path: &PathBuf) -> bool {
  239. self.paths_to_sections.contains_key(path)
  240. }
  241. /// Used in rebuild, to check if we know it already
  242. pub fn contains_page(&self, path: &PathBuf) -> bool {
  243. self.paths_to_pages.contains_key(path)
  244. }
  245. }