2019-01-27 23:34:18 +00:00
|
|
|
/// Populated while receiving events from the markdown parser
|
2017-06-16 04:00:48 +00:00
|
|
|
#[derive(Debug, PartialEq, Clone, Serialize)]
|
|
|
|
pub struct Header {
|
|
|
|
#[serde(skip_serializing)]
|
|
|
|
pub level: i32,
|
|
|
|
pub id: String,
|
|
|
|
pub permalink: String,
|
2019-01-27 23:34:18 +00:00
|
|
|
pub title: String,
|
2017-06-16 04:00:48 +00:00
|
|
|
pub children: Vec<Header>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Header {
|
2019-01-27 23:34:18 +00:00
|
|
|
pub fn new(level: i32) -> Header {
|
2017-06-16 04:00:48 +00:00
|
|
|
Header {
|
|
|
|
level,
|
|
|
|
id: String::new(),
|
|
|
|
permalink: String::new(),
|
|
|
|
title: String::new(),
|
2019-01-27 23:34:18 +00:00
|
|
|
children: Vec::new(),
|
2017-09-27 14:09:13 +00:00
|
|
|
}
|
|
|
|
}
|
2017-06-16 04:00:48 +00:00
|
|
|
}
|
|
|
|
|
2019-01-27 23:34:18 +00:00
|
|
|
impl Default for Header {
|
2017-06-16 04:00:48 +00:00
|
|
|
fn default() -> Self {
|
2019-01-27 23:34:18 +00:00
|
|
|
Header::new(0)
|
2017-06-16 04:00:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Converts the flat temp headers into a nested set of headers
|
|
|
|
/// representing the hierarchy
|
2019-01-27 23:34:18 +00:00
|
|
|
pub fn make_table_of_contents(headers: Vec<Header>) -> Vec<Header> {
|
2017-06-16 04:00:48 +00:00
|
|
|
let mut toc = vec![];
|
2019-01-27 23:34:18 +00:00
|
|
|
'parent: for header in headers {
|
|
|
|
if toc.is_empty() {
|
|
|
|
toc.push(header);
|
2017-06-16 04:00:48 +00:00
|
|
|
continue;
|
|
|
|
}
|
2019-01-27 23:34:18 +00:00
|
|
|
|
|
|
|
// See if we have to insert as a child of a previous header
|
|
|
|
for h in toc.iter_mut().rev() {
|
|
|
|
// Look in its children first
|
|
|
|
for child in h.children.iter_mut().rev() {
|
|
|
|
if header.level > child.level {
|
|
|
|
child.children.push(header);
|
|
|
|
continue 'parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if header.level > h.level {
|
|
|
|
h.children.push(header);
|
|
|
|
continue 'parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nop, just insert it
|
|
|
|
toc.push(header)
|
2017-06-16 04:00:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
toc
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn can_make_basic_toc() {
|
2019-01-27 23:34:18 +00:00
|
|
|
let input = vec![Header::new(1), Header::new(1), Header::new(1)];
|
|
|
|
let toc = make_table_of_contents(input);
|
2017-06-16 04:00:48 +00:00
|
|
|
assert_eq!(toc.len(), 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn can_make_more_complex_toc() {
|
|
|
|
let input = vec![
|
2019-01-27 23:34:18 +00:00
|
|
|
Header::new(1),
|
|
|
|
Header::new(2),
|
|
|
|
Header::new(2),
|
|
|
|
Header::new(3),
|
|
|
|
Header::new(2),
|
|
|
|
Header::new(1),
|
|
|
|
Header::new(2),
|
|
|
|
Header::new(3),
|
|
|
|
Header::new(3),
|
2017-06-16 04:00:48 +00:00
|
|
|
];
|
2019-01-27 23:34:18 +00:00
|
|
|
let toc = make_table_of_contents(input);
|
2017-06-16 04:00:48 +00:00
|
|
|
assert_eq!(toc.len(), 2);
|
|
|
|
assert_eq!(toc[0].children.len(), 3);
|
|
|
|
assert_eq!(toc[1].children.len(), 1);
|
|
|
|
assert_eq!(toc[0].children[1].children.len(), 1);
|
|
|
|
assert_eq!(toc[1].children[0].children.len(), 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn can_make_messy_toc() {
|
|
|
|
let input = vec![
|
2019-01-27 23:34:18 +00:00
|
|
|
Header::new(3),
|
|
|
|
Header::new(2),
|
|
|
|
Header::new(2),
|
|
|
|
Header::new(3),
|
|
|
|
Header::new(2),
|
|
|
|
Header::new(1),
|
|
|
|
Header::new(4),
|
2017-06-16 04:00:48 +00:00
|
|
|
];
|
2019-01-27 23:34:18 +00:00
|
|
|
let toc = make_table_of_contents(input);
|
|
|
|
println!("{:#?}", toc);
|
2017-06-16 04:00:48 +00:00
|
|
|
assert_eq!(toc.len(), 5);
|
|
|
|
assert_eq!(toc[2].children.len(), 1);
|
|
|
|
assert_eq!(toc[4].children.len(), 1);
|
|
|
|
}
|
|
|
|
}
|