1use crate::{Event, Tag};
2use std::cell::RefCell;
3use std::collections::VecDeque;
4use std::ops::Range;
5
6#[derive(Debug, Clone)]
7struct Node<'e>(u32, Vec<Event<'e>>);
8
9impl<'e> Node<'e> {
10 fn new(level: u32) -> Self {
11 Self(level, Vec::with_capacity(1))
12 }
13
14 fn push(&mut self, e: Event<'e>) {
15 self.1.push(e)
16 }
17}
18
19#[derive(Debug, Clone)]
20struct List<'e>(RefCell<VecDeque<Node<'e>>>);
21
22impl<'e> List<'e> {
23 fn new() -> Self {
24 List(RefCell::new(VecDeque::new()))
25 }
26
27 fn create(&self, level: u32) {
28 self.0.borrow_mut().push_back(Node::new(level));
29 }
30
31 fn add(&self, event: Event<'e>) {
32 let index = self.0.borrow().len() - 1;
34 self.0.borrow_mut().get_mut(index).unwrap().push(event);
35 }
36}
37
38#[derive(Debug, Clone)]
39pub struct ToC<'e> {
40 range: Range<u32>,
41 list: List<'e>,
42}
43
44impl<'e> ToC<'e> {
45 pub fn new(range: Range<u32>) -> Self {
46 Self {
47 range,
48 list: List::new(),
49 }
50 }
51
52 pub fn start<'f>(&self, event: &Event<'f>) -> bool {
53 match &event {
54 Event::Start(Tag::Heading(n)) if self.range.contains(&n) => {
55 self.list.create(*n);
56 true
57 }
58 _ => false,
59 }
60 }
61
62 pub fn end<'f>(&self, event: &Event<'f>) -> bool {
63 match &event {
64 Event::End(Tag::Heading(_)) => true,
67 _ => false,
68 }
69 }
70
71 pub fn within(&self, e: Event<'e>) -> Option<Event<'e>> {
72 self.list.add(e.clone());
73 Some(e)
74 }
75
76 pub fn generate(&self) -> impl Iterator<Item = Event<'e>> {
77 let mut v = vec![];
78 v.push(Event::Html("<div class=\"sidebar toc\">\n".into()));
79 let mut indent = if self.range.start - 1 > 0 {
80 self.range.start - 1
81 } else {
82 0
83 };
84 for Node(level, ref mut events) in self.list.0.borrow_mut().iter_mut() {
85 push_tag(&mut v, indent, *level);
86 v.push(Event::Start(Tag::Item));
87 v.append(events);
88 v.push(Event::End(Tag::Item));
89 indent = *level;
90 }
91 while indent > 0 {
92 v.push(Event::End(Tag::List(None)));
93 indent -= 1;
94 }
95 v.push(Event::Html("</div>\n".into()));
96 v.into_iter()
97 }
98}
99
100fn push_tag<'e>(v: &mut Vec<Event<'e>>, indent: u32, level: u32) {
101 let mut sub = if level > indent {
102 level - indent
103 } else {
104 indent - level
105 };
106 while sub > 0 {
107 if level > indent {
108 v.push(Event::Start(Tag::List(None)));
109 sub -= 1;
110 } else {
111 v.push(Event::End(Tag::List(None)));
112 sub -= 1;
113 }
114 }
115}