Section numbering

This commit is contained in:
ef3d0c3e 2024-08-02 14:10:17 +02:00
parent d91279c1f2
commit 7b081be97b
3 changed files with 60 additions and 19 deletions

View file

@ -1,3 +1,4 @@
use std::cell::Ref;
use std::cell::RefCell; use std::cell::RefCell;
use std::cell::RefMut; use std::cell::RefMut;
use std::collections::HashMap; use std::collections::HashMap;
@ -20,6 +21,8 @@ pub struct Compiler {
cache: Option<RefCell<Connection>>, cache: Option<RefCell<Connection>>,
reference_count: RefCell<HashMap<String, HashMap<String, usize>>>, reference_count: RefCell<HashMap<String, HashMap<String, usize>>>,
// TODO: External references, i.e resolved later // TODO: External references, i.e resolved later
sections_counter: RefCell<Vec<usize>>,
} }
impl Compiler { impl Compiler {
@ -35,9 +38,34 @@ impl Compiler {
target, target,
cache: cache.map(|con| RefCell::new(con)), cache: cache.map(|con| RefCell::new(con)),
reference_count: RefCell::new(HashMap::new()), reference_count: RefCell::new(HashMap::new()),
sections_counter: RefCell::new(vec![]),
} }
} }
/// Gets the section counter for a given depth
/// This function modifies the section counter
pub fn section_counter(&self, depth: usize) -> Ref<'_, Vec<usize>>
{
// Increment current counter
if self.sections_counter.borrow().len() == depth {
self.sections_counter.borrow_mut().last_mut()
.map(|id| *id += 1);
return Ref::map(self.sections_counter.borrow(), |b| &*b);
}
// Close
while self.sections_counter.borrow().len() > depth {
self.sections_counter.borrow_mut().pop();
}
// Open
while self.sections_counter.borrow().len() < depth {
self.sections_counter.borrow_mut().push(1);
}
Ref::map(self.sections_counter.borrow(), |b| &*b)
}
/// Sanitizes text for a [`Target`] /// Sanitizes text for a [`Target`]
pub fn sanitize<S: AsRef<str>>(target: Target, str: S) -> String { pub fn sanitize<S: AsRef<str>>(target: Target, str: S) -> String {
match target { match target {

View file

@ -282,7 +282,7 @@ impl RegexRule for ScriptRule {
mod tests { mod tests {
use super::*; use super::*;
use crate::elements::link::Link; use crate::elements::link::Link;
use crate::elements::list::ListEntry; use crate::elements::list::ListEntry;
use crate::elements::list::ListMarker; use crate::elements::list::ListMarker;
use crate::elements::paragraph::Paragraph; use crate::elements::paragraph::Paragraph;
use crate::elements::style::Style; use crate::elements::style::Style;

View file

@ -17,6 +17,7 @@ use mlua::Error::BadArgument;
use mlua::Function; use mlua::Function;
use mlua::Lua; use mlua::Lua;
use regex::Regex; use regex::Regex;
use section_kind::NO_NUMBER;
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
@ -38,13 +39,25 @@ impl Element for Section {
fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result<String, String> { fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result<String, String> {
match compiler.target() { match compiler.target() {
Target::HTML => { Target::HTML => {
let mut number = String::new();
if (self.kind & NO_NUMBER) != NO_NUMBER {
let numbering = compiler.section_counter(self.depth);
number = numbering
.iter()
.map(|n| n.to_string())
.collect::<Vec<_>>()
.join(".");
number += " ";
}
Ok(format!( Ok(format!(
r#"<h{0} id="{1}">{2}</h{0}>"#, r#"<h{0} id="{1}">{number}{2}</h{0}>"#,
self.depth, self.depth,
Compiler::refname(compiler.target(), self.title.as_str()), Compiler::refname(compiler.target(), self.title.as_str()),
Compiler::sanitize(compiler.target(), self.title.as_str()) Compiler::sanitize(compiler.target(), self.title.as_str())
)) ))
}, }
Target::LATEX => Err("Unimplemented compiler".to_string()), Target::LATEX => Err("Unimplemented compiler".to_string()),
} }
} }
@ -136,15 +149,15 @@ impl RegexRule for SectionRule {
}; };
// [Optional] Reference name // [Optional] Reference name
let section_refname = matches.get(2).map_or_else( let section_refname =
|| None, matches.get(2).map_or_else(
|refname| { || None,
// Check for duplicate reference |refname| {
if let Some(elem_reference) = document.get_reference(refname.as_str()) // Check for duplicate reference
{ if let Some(elem_reference) = document.get_reference(refname.as_str()) {
let elem = document.get_from_reference(&elem_reference).unwrap(); let elem = document.get_from_reference(&elem_reference).unwrap();
result.push( result.push(
Report::build(ReportKind::Warning, token.source(), refname.start()) Report::build(ReportKind::Warning, token.source(), refname.start())
.with_message("Duplicate reference name") .with_message("Duplicate reference name")
.with_label( .with_label(
@ -163,10 +176,10 @@ impl RegexRule for SectionRule {
.with_color(parser.colors().warning)) .with_color(parser.colors().warning))
.with_note(format!("Previous reference was overwritten")) .with_note(format!("Previous reference was overwritten"))
.finish()); .finish());
} }
Some(refname.as_str().to_string()) Some(refname.as_str().to_string())
}, },
); );
// Section kind // Section kind
let section_kind = match matches.get(3) { let section_kind = match matches.get(3) {