Table of content
This commit is contained in:
parent
da6349e2f5
commit
1cd0e2ffc4
2 changed files with 107 additions and 8 deletions
|
@ -9,6 +9,8 @@ use crate::document::document::CrossReference;
|
||||||
use crate::document::document::Document;
|
use crate::document::document::Document;
|
||||||
use crate::document::document::ElemReference;
|
use crate::document::document::ElemReference;
|
||||||
use crate::document::variable::Variable;
|
use crate::document::variable::Variable;
|
||||||
|
use crate::elements::section::section_kind;
|
||||||
|
use crate::elements::section::Section;
|
||||||
|
|
||||||
use super::postprocess::PostProcess;
|
use super::postprocess::PostProcess;
|
||||||
|
|
||||||
|
@ -226,6 +228,93 @@ impl<'a> Compiler<'a> {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn toc(&self, document: &dyn Document) -> String {
|
||||||
|
let toc_title = if let Some(title) = document.get_variable("toc.title") {
|
||||||
|
title
|
||||||
|
} else {
|
||||||
|
return String::new();
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut result = String::new();
|
||||||
|
let mut sections: Vec<(&Section, usize)> = vec![];
|
||||||
|
// Find last section with given depth
|
||||||
|
fn last_matching(depth: usize, sections: &Vec<(&Section, usize)>) -> Option<usize> {
|
||||||
|
for (idx, (section, _number)) in sections.iter().rev().enumerate() {
|
||||||
|
if section.depth < depth {
|
||||||
|
return None;
|
||||||
|
} else if section.depth == depth {
|
||||||
|
return Some(sections.len() - idx - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
let content_borrow = document.content().borrow();
|
||||||
|
for elem in content_borrow.iter() {
|
||||||
|
if let Some(section) = elem.downcast_ref::<Section>() {
|
||||||
|
if section.kind & section_kind::NO_TOC != 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let last = last_matching(section.depth, §ions);
|
||||||
|
if let Some(last) = last {
|
||||||
|
if sections[last].0.kind & section_kind::NO_NUMBER != 0 {
|
||||||
|
sections.push((section, sections[last].1));
|
||||||
|
} else {
|
||||||
|
sections.push((section, sections[last].1 + 1))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sections.push((section, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.target() {
|
||||||
|
Target::HTML => {
|
||||||
|
let match_depth = |current: usize, target: usize| -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
for _ in current..target {
|
||||||
|
result += "<ol>";
|
||||||
|
}
|
||||||
|
for _ in target..current {
|
||||||
|
result += "</ol>";
|
||||||
|
}
|
||||||
|
result
|
||||||
|
};
|
||||||
|
result += "<div class=\"toc\">";
|
||||||
|
result += format!(
|
||||||
|
"<span>{}</span>",
|
||||||
|
Compiler::sanitize(self.target(), toc_title.to_string())
|
||||||
|
)
|
||||||
|
.as_str();
|
||||||
|
let mut current_depth = 0;
|
||||||
|
for (section, number) in sections {
|
||||||
|
result += match_depth(current_depth, section.depth).as_str();
|
||||||
|
if section.kind & section_kind::NO_NUMBER != 0 {
|
||||||
|
result += format!(
|
||||||
|
"<li><a href=\"#{}\">{}</a></li>",
|
||||||
|
Compiler::refname(self.target(), section.title.as_str()),
|
||||||
|
Compiler::sanitize(self.target(), section.title.as_str())
|
||||||
|
)
|
||||||
|
.as_str();
|
||||||
|
} else {
|
||||||
|
result += format!(
|
||||||
|
"<li value=\"{number}\"><a href=\"#{}\">{}</a></li>",
|
||||||
|
Compiler::refname(self.target(), section.title.as_str()),
|
||||||
|
Compiler::sanitize(self.target(), section.title.as_str())
|
||||||
|
)
|
||||||
|
.as_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
current_depth = section.depth;
|
||||||
|
}
|
||||||
|
match_depth(current_depth, 0);
|
||||||
|
result += "</div>";
|
||||||
|
}
|
||||||
|
_ => todo!(""),
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
pub fn compile(&self, document: &dyn Document) -> (CompiledDocument, PostProcess) {
|
pub fn compile(&self, document: &dyn Document) -> (CompiledDocument, PostProcess) {
|
||||||
let borrow = document.content().borrow();
|
let borrow = document.content().borrow();
|
||||||
|
|
||||||
|
@ -234,6 +323,10 @@ impl<'a> Compiler<'a> {
|
||||||
|
|
||||||
// Body
|
// Body
|
||||||
let mut body = r#"<div class="content">"#.to_string();
|
let mut body = r#"<div class="content">"#.to_string();
|
||||||
|
|
||||||
|
// Table of content
|
||||||
|
body += self.toc(document).as_str();
|
||||||
|
|
||||||
for i in 0..borrow.len() {
|
for i in 0..borrow.len() {
|
||||||
let elem = &borrow[i];
|
let elem = &borrow[i];
|
||||||
|
|
||||||
|
@ -378,8 +471,14 @@ mod tests {
|
||||||
assert_eq!(Compiler::sanitize(Target::HTML, "<"), "&lt;");
|
assert_eq!(Compiler::sanitize(Target::HTML, "<"), "&lt;");
|
||||||
assert_eq!(Compiler::sanitize(Target::HTML, "\""), """);
|
assert_eq!(Compiler::sanitize(Target::HTML, "\""), """);
|
||||||
|
|
||||||
assert_eq!(Compiler::sanitize_format(Target::HTML, "{<>&\"}"), "{<>&\"}");
|
assert_eq!(
|
||||||
assert_eq!(Compiler::sanitize_format(Target::HTML, "{{<>}}"), "{{<>}}");
|
Compiler::sanitize_format(Target::HTML, "{<>&\"}"),
|
||||||
|
"{<>&\"}"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Compiler::sanitize_format(Target::HTML, "{{<>}}"),
|
||||||
|
"{{<>}}"
|
||||||
|
);
|
||||||
assert_eq!(Compiler::sanitize_format(Target::HTML, "{{<"), "{{<");
|
assert_eq!(Compiler::sanitize_format(Target::HTML, "{{<"), "{{<");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,17 +28,17 @@ use super::reference::InternalReference;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Section {
|
pub struct Section {
|
||||||
pub(self) location: Token,
|
pub location: Token,
|
||||||
/// Title of the section
|
/// Title of the section
|
||||||
pub(self) title: String,
|
pub title: String,
|
||||||
/// Depth i.e number of '#'
|
/// Depth i.e number of '#'
|
||||||
pub(self) depth: usize,
|
pub depth: usize,
|
||||||
/// [`section_kind`]
|
/// [`section_kind`]
|
||||||
pub(self) kind: u8,
|
pub kind: u8,
|
||||||
/// Section reference name
|
/// Section reference name
|
||||||
pub(self) reference: Option<String>,
|
pub reference: Option<String>,
|
||||||
/// Style of the section
|
/// Style of the section
|
||||||
pub(self) style: Rc<section_style::SectionStyle>,
|
pub style: Rc<section_style::SectionStyle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element for Section {
|
impl Element for Section {
|
||||||
|
|
Loading…
Reference in a new issue