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.

355 lines
13KB

  1. use std::collections::{HashMap, HashSet};
  2. use std::path::{Path, PathBuf};
  3. use slotmap::{DenseSlotMap, Key};
  4. use front_matter::SortBy;
  5. use content::{Page, Section};
  6. use sorting::{find_siblings, sort_pages_by_date, sort_pages_by_weight};
  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. pub 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 (root_path, index_path) = self
  70. .sections
  71. .values()
  72. .find(|s| s.is_index())
  73. .map(|s| (s.file.parent.clone(), s.file.path.clone()))
  74. .unwrap();
  75. let root_key = self.paths_to_sections[&index_path];
  76. // We are going to get both the ancestors and grandparents for each section in one go
  77. let mut ancestors: HashMap<PathBuf, Vec<_>> = HashMap::new();
  78. let mut subsections: HashMap<PathBuf, Vec<_>> = HashMap::new();
  79. for section in self.sections.values_mut() {
  80. // Make sure the pages of a section are empty since we can call that many times on `serve`
  81. section.pages = vec![];
  82. section.ignored_pages = vec![];
  83. if let Some(ref grand_parent) = section.file.grand_parent {
  84. subsections
  85. .entry(grand_parent.join("_index.md"))
  86. .or_insert_with(|| vec![])
  87. .push(section.file.path.clone());
  88. }
  89. // Index has no ancestors, no need to go through it
  90. if section.is_index() {
  91. ancestors.insert(section.file.path.clone(), vec![]);
  92. continue;
  93. }
  94. let mut path = root_path.clone();
  95. // Index section is the first ancestor of every single section
  96. let mut parents = vec![root_key];
  97. for component in &section.file.components {
  98. path = path.join(component);
  99. // Skip itself
  100. if path == section.file.parent {
  101. continue;
  102. }
  103. if let Some(section_key) = self.paths_to_sections.get(&path.join("_index.md")) {
  104. parents.push(*section_key);
  105. }
  106. }
  107. ancestors.insert(section.file.path.clone(), parents);
  108. }
  109. for (key, page) in &mut self.pages {
  110. let mut parent_section_path = page.file.parent.join("_index.md");
  111. while let Some(section_key) = self.paths_to_sections.get(&parent_section_path) {
  112. let parent_is_transparent;
  113. // We need to get a reference to a section later so keep the scope of borrowing small
  114. {
  115. let mut section = self.sections.get_mut(*section_key).unwrap();
  116. section.pages.push(key);
  117. parent_is_transparent = section.meta.transparent;
  118. }
  119. page.ancestors =
  120. ancestors.get(&parent_section_path).cloned().unwrap_or_else(|| vec![]);
  121. // Don't forget to push the actual parent
  122. page.ancestors.push(*section_key);
  123. // Find the page template if one of a parent has page_template set
  124. // Stops after the first one found, keep in mind page.ancestors
  125. // is [index, ..., parent] so we need to reverse it first
  126. if page.meta.template.is_none() {
  127. for ancestor in page.ancestors.iter().rev() {
  128. let s = self.sections.get(*ancestor).unwrap();
  129. if s.meta.page_template.is_some() {
  130. page.meta.template = s.meta.page_template.clone();
  131. break;
  132. }
  133. }
  134. }
  135. if !parent_is_transparent {
  136. break;
  137. }
  138. // We've added `_index.md` so if we are here so we need to go up twice
  139. match parent_section_path.clone().parent().unwrap().parent() {
  140. Some(parent) => parent_section_path = parent.join("_index.md"),
  141. None => break,
  142. }
  143. }
  144. }
  145. self.sort_sections_pages();
  146. let sections = self.paths_to_sections.clone();
  147. let mut sections_weight = HashMap::new();
  148. for (key, section) in &self.sections {
  149. sections_weight.insert(key, section.meta.weight);
  150. }
  151. for section in self.sections.values_mut() {
  152. if let Some(ref children) = subsections.get(&section.file.path) {
  153. let mut children: Vec<_> = children.iter().map(|p| sections[p]).collect();
  154. children.sort_by(|a, b| sections_weight[a].cmp(&sections_weight[b]));
  155. section.subsections = children;
  156. }
  157. section.ancestors =
  158. ancestors.get(&section.file.path).cloned().unwrap_or_else(|| vec![]);
  159. }
  160. }
  161. /// Sort all sections pages
  162. pub fn sort_sections_pages(&mut self) {
  163. let mut updates = HashMap::new();
  164. for (key, section) in &self.sections {
  165. let (sorted_pages, cannot_be_sorted_pages) = match section.meta.sort_by {
  166. SortBy::None => continue,
  167. SortBy::Date => {
  168. let data = section
  169. .pages
  170. .iter()
  171. .map(|k| {
  172. if let Some(page) = self.pages.get(*k) {
  173. (k, page.meta.datetime, page.permalink.as_ref())
  174. } else {
  175. unreachable!("Sorting got an unknown page")
  176. }
  177. })
  178. .collect();
  179. sort_pages_by_date(data)
  180. }
  181. SortBy::Weight => {
  182. let data = section
  183. .pages
  184. .iter()
  185. .map(|k| {
  186. if let Some(page) = self.pages.get(*k) {
  187. (k, page.meta.weight, page.permalink.as_ref())
  188. } else {
  189. unreachable!("Sorting got an unknown page")
  190. }
  191. })
  192. .collect();
  193. sort_pages_by_weight(data)
  194. }
  195. };
  196. updates.insert(key, (sorted_pages, cannot_be_sorted_pages, section.meta.sort_by));
  197. }
  198. for (key, (sorted, cannot_be_sorted, sort_by)) in updates {
  199. // Find sibling between sorted pages first
  200. let with_siblings = find_siblings(
  201. sorted
  202. .iter()
  203. .map(|k| {
  204. if let Some(page) = self.pages.get(*k) {
  205. (k, page.is_draft())
  206. } else {
  207. unreachable!("Sorting got an unknown page")
  208. }
  209. })
  210. .collect(),
  211. );
  212. for (k2, val1, val2) in with_siblings {
  213. if let Some(page) = self.pages.get_mut(k2) {
  214. match sort_by {
  215. SortBy::Date => {
  216. page.earlier = val2;
  217. page.later = val1;
  218. }
  219. SortBy::Weight => {
  220. page.lighter = val1;
  221. page.heavier = val2;
  222. }
  223. SortBy::None => unreachable!("Impossible to find siblings in SortBy::None"),
  224. }
  225. } else {
  226. unreachable!("Sorting got an unknown page")
  227. }
  228. }
  229. if let Some(s) = self.sections.get_mut(key) {
  230. s.pages = sorted;
  231. s.ignored_pages = cannot_be_sorted;
  232. }
  233. }
  234. }
  235. /// Find all the orphan pages: pages that are in a folder without an `_index.md`
  236. pub fn get_all_orphan_pages(&self) -> Vec<&Page> {
  237. let pages_in_sections =
  238. self.sections.values().flat_map(|s| &s.pages).collect::<HashSet<_>>();
  239. self.pages
  240. .iter()
  241. .filter(|(key, _)| !pages_in_sections.contains(&key))
  242. .map(|(_, page)| page)
  243. .collect()
  244. }
  245. pub fn find_parent_section<P: AsRef<Path>>(&self, path: P) -> Option<&Section> {
  246. let page_key = self.paths_to_pages[path.as_ref()];
  247. for s in self.sections.values() {
  248. if s.pages.contains(&page_key) {
  249. return Some(s);
  250. }
  251. }
  252. None
  253. }
  254. /// Only used in tests
  255. pub fn get_section_key<P: AsRef<Path>>(&self, path: P) -> Option<&Key> {
  256. self.paths_to_sections.get(path.as_ref())
  257. }
  258. pub fn get_section<P: AsRef<Path>>(&self, path: P) -> Option<&Section> {
  259. self.sections.get(self.paths_to_sections.get(path.as_ref()).cloned().unwrap_or_default())
  260. }
  261. pub fn get_section_mut<P: AsRef<Path>>(&mut self, path: P) -> Option<&mut Section> {
  262. self.sections
  263. .get_mut(self.paths_to_sections.get(path.as_ref()).cloned().unwrap_or_default())
  264. }
  265. pub fn get_section_by_key(&self, key: Key) -> &Section {
  266. self.sections.get(key).unwrap()
  267. }
  268. pub fn get_section_mut_by_key(&mut self, key: Key) -> &mut Section {
  269. self.sections.get_mut(key).unwrap()
  270. }
  271. pub fn get_section_path_by_key(&self, key: Key) -> &str {
  272. &self.get_section_by_key(key).file.relative
  273. }
  274. pub fn get_page<P: AsRef<Path>>(&self, path: P) -> Option<&Page> {
  275. self.pages.get(self.paths_to_pages.get(path.as_ref()).cloned().unwrap_or_default())
  276. }
  277. pub fn get_page_by_key(&self, key: Key) -> &Page {
  278. self.pages.get(key).unwrap()
  279. }
  280. pub fn get_page_mut_by_key(&mut self, key: Key) -> &mut Page {
  281. self.pages.get_mut(key).unwrap()
  282. }
  283. pub fn remove_section<P: AsRef<Path>>(&mut self, path: P) -> Option<Section> {
  284. if let Some(k) = self.paths_to_sections.remove(path.as_ref()) {
  285. self.sections.remove(k)
  286. } else {
  287. None
  288. }
  289. }
  290. pub fn remove_page<P: AsRef<Path>>(&mut self, path: P) -> Option<Page> {
  291. if let Some(k) = self.paths_to_pages.remove(path.as_ref()) {
  292. self.pages.remove(k)
  293. } else {
  294. None
  295. }
  296. }
  297. /// Used in rebuild, to check if we know it already
  298. pub fn contains_section<P: AsRef<Path>>(&self, path: P) -> bool {
  299. self.paths_to_sections.contains_key(path.as_ref())
  300. }
  301. /// Used in rebuild, to check if we know it already
  302. pub fn contains_page<P: AsRef<Path>>(&self, path: P) -> bool {
  303. self.paths_to_pages.contains_key(path.as_ref())
  304. }
  305. }