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.

table_of_contents.rs 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /// Populated while receiving events from the markdown parser
  2. #[derive(Debug, PartialEq, Clone, Serialize)]
  3. pub struct Header {
  4. #[serde(skip_serializing)]
  5. pub level: i32,
  6. pub id: String,
  7. pub permalink: String,
  8. pub title: String,
  9. pub children: Vec<Header>,
  10. }
  11. impl Header {
  12. pub fn new(level: i32) -> Header {
  13. Header {
  14. level,
  15. id: String::new(),
  16. permalink: String::new(),
  17. title: String::new(),
  18. children: Vec::new(),
  19. }
  20. }
  21. }
  22. impl Default for Header {
  23. fn default() -> Self {
  24. Header::new(0)
  25. }
  26. }
  27. /// Converts the flat temp headers into a nested set of headers
  28. /// representing the hierarchy
  29. pub fn make_table_of_contents(headers: Vec<Header>) -> Vec<Header> {
  30. let mut toc = vec![];
  31. 'parent: for header in headers {
  32. if toc.is_empty() {
  33. toc.push(header);
  34. continue;
  35. }
  36. // See if we have to insert as a child of a previous header
  37. for h in toc.iter_mut().rev() {
  38. // Look in its children first
  39. for child in h.children.iter_mut().rev() {
  40. if header.level > child.level {
  41. child.children.push(header);
  42. continue 'parent;
  43. }
  44. }
  45. if header.level > h.level {
  46. h.children.push(header);
  47. continue 'parent;
  48. }
  49. }
  50. // Nop, just insert it
  51. toc.push(header)
  52. }
  53. toc
  54. }
  55. #[cfg(test)]
  56. mod tests {
  57. use super::*;
  58. #[test]
  59. fn can_make_basic_toc() {
  60. let input = vec![Header::new(1), Header::new(1), Header::new(1)];
  61. let toc = make_table_of_contents(input);
  62. assert_eq!(toc.len(), 3);
  63. }
  64. #[test]
  65. fn can_make_more_complex_toc() {
  66. let input = vec![
  67. Header::new(1),
  68. Header::new(2),
  69. Header::new(2),
  70. Header::new(3),
  71. Header::new(2),
  72. Header::new(1),
  73. Header::new(2),
  74. Header::new(3),
  75. Header::new(3),
  76. ];
  77. let toc = make_table_of_contents(input);
  78. assert_eq!(toc.len(), 2);
  79. assert_eq!(toc[0].children.len(), 3);
  80. assert_eq!(toc[1].children.len(), 1);
  81. assert_eq!(toc[0].children[1].children.len(), 1);
  82. assert_eq!(toc[1].children[0].children.len(), 2);
  83. }
  84. #[test]
  85. fn can_make_messy_toc() {
  86. let input = vec![
  87. Header::new(3),
  88. Header::new(2),
  89. Header::new(2),
  90. Header::new(3),
  91. Header::new(2),
  92. Header::new(1),
  93. Header::new(4),
  94. ];
  95. let toc = make_table_of_contents(input);
  96. println!("{:#?}", toc);
  97. assert_eq!(toc.len(), 5);
  98. assert_eq!(toc[2].children.len(), 1);
  99. assert_eq!(toc[4].children.len(), 1);
  100. }
  101. }