WIP Navigation sorting
This commit is contained in:
parent
90cf691737
commit
0982527944
5 changed files with 131 additions and 20 deletions
|
@ -25,3 +25,8 @@ function make_doc(categories, title, page_title)
|
|||
nml.variable.insert("compiler.output", page_title .. ".html")
|
||||
end
|
||||
>@
|
||||
|
||||
@@style.section = {
|
||||
"link_pos": "Before",
|
||||
"link": ["", "🔗 ", " "]
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use super::compiler::Target;
|
|||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct NavEntry {
|
||||
pub(self) entries: Vec<(String, String)>,
|
||||
pub(self) entries: Vec<(String, String, Option<String>)>,
|
||||
pub(self) children: HashMap<String, NavEntry>,
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ impl NavEntry {
|
|||
depth: usize,
|
||||
) {
|
||||
// Orphans = Links
|
||||
for (title, path) in &entry.entries {
|
||||
for (title, path, _) in &entry.entries {
|
||||
result.push_str(
|
||||
format!(
|
||||
r#"<li><a href="{}">{}</a></li>"#,
|
||||
|
@ -75,6 +75,36 @@ impl NavEntry {
|
|||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Gets the insert index of the entry inside an already sorted entry list
|
||||
fn sort_entry(
|
||||
title: &String,
|
||||
previous: &Option<String>,
|
||||
entries: &Vec<(String, String, Option<String>)>,
|
||||
) -> usize {
|
||||
let mut insert_at = 0;
|
||||
if let Some(previous) = &previous
|
||||
// Using sort key
|
||||
{
|
||||
for (i, (ent_title, _, _)) in entries.iter().enumerate() {
|
||||
if ent_title == previous {
|
||||
insert_at = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then sort alphabetically
|
||||
for (ent_title, _, ent_previous) in entries.iter().skip(insert_at) {
|
||||
if (previous.is_some() && ent_previous != previous) || ent_title > title {
|
||||
break;
|
||||
}
|
||||
|
||||
insert_at += 1;
|
||||
}
|
||||
|
||||
insert_at
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_navigation(docs: &Vec<CompiledDocument>) -> Result<NavEntry, String> {
|
||||
|
@ -83,12 +113,16 @@ pub fn create_navigation(docs: &Vec<CompiledDocument>) -> Result<NavEntry, Strin
|
|||
children: HashMap::new(),
|
||||
};
|
||||
|
||||
// All paths (for duplicate checking)
|
||||
let mut all_paths = HashMap::new();
|
||||
|
||||
for doc in docs {
|
||||
let cat = doc.get_variable("nav.category");
|
||||
let subcat = doc.get_variable("nav.subcategory");
|
||||
let title = doc
|
||||
.get_variable("nav.title")
|
||||
.or(doc.get_variable("doc.title"));
|
||||
let previous = doc.get_variable("nav.previous").map(|s| s.clone());
|
||||
let path = doc.get_variable("compiler.output");
|
||||
|
||||
let (title, path) = match (title, path) {
|
||||
|
@ -142,8 +176,67 @@ pub fn create_navigation(docs: &Vec<CompiledDocument>) -> Result<NavEntry, Strin
|
|||
&mut nav
|
||||
};
|
||||
|
||||
pent.entries.push((title.clone(), path.clone()))
|
||||
// Find duplicates titles in current parent
|
||||
for (ent_title, _, _) in &pent.entries {
|
||||
if ent_title == title {
|
||||
return Err(format!(
|
||||
"Conflicting entry title `{title}` for entries with the same parent: ({})",
|
||||
pent.entries
|
||||
.iter()
|
||||
.map(|(title, _, _)| title.clone())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Find duplicate paths
|
||||
if let Some(dup_title) = all_paths.get(path) {
|
||||
return Err(format!("Conflicting paths: `{path}`. Previously used for entry: `{dup_title}`, conflicting use in `{title}`"));
|
||||
}
|
||||
all_paths.insert(path.clone(), title.clone());
|
||||
|
||||
pent.entries.insert(
|
||||
NavEntry::sort_entry(title, &previous, &pent.entries),
|
||||
(title.clone(), path.clone(), previous),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(nav)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sort() {
|
||||
let entries: Vec<(String, String, Option<String>)> = vec![
|
||||
("Root".into(), "".into(), None),
|
||||
("First".into(), "".into(), Some("Root".into())),
|
||||
("1".into(), "".into(), Some("First".into())),
|
||||
("2".into(), "".into(), Some("First".into())),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
NavEntry::sort_entry(&"E".into(), &Some("Root".into()), &entries),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
NavEntry::sort_entry(&"G".into(), &Some("Root".into()), &entries),
|
||||
2
|
||||
);
|
||||
// Orphans
|
||||
assert_eq!(NavEntry::sort_entry(&"Q".into(), &None, &entries), 0);
|
||||
assert_eq!(NavEntry::sort_entry(&"S".into(), &None, &entries), 4);
|
||||
|
||||
assert_eq!(
|
||||
NavEntry::sort_entry(&"1.1".into(), &Some("First".into()), &entries),
|
||||
3
|
||||
);
|
||||
assert_eq!(
|
||||
NavEntry::sort_entry(&"2.1".into(), &Some("First".into()), &entries),
|
||||
4
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ impl ReferenceRule {
|
|||
),
|
||||
);
|
||||
Self {
|
||||
re: [Regex::new(r"§\{(.*)\}(\[((?:\\.|[^\\\\])*?)\])?").unwrap()],
|
||||
re: [Regex::new(r"§\{(.*?)\}(\[((?:\\.|[^\\\\])*?)\])?").unwrap()],
|
||||
properties: PropertyParser{ properties: props },
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,16 +46,17 @@ impl Element for Section {
|
|||
match compiler.target() {
|
||||
Target::HTML => {
|
||||
// Section numbering
|
||||
let number = if (self.kind & section_kind::NO_NUMBER) == section_kind::NO_NUMBER {
|
||||
let number = if (self.kind & section_kind::NO_NUMBER) != section_kind::NO_NUMBER {
|
||||
let numbering = compiler.section_counter(self.depth);
|
||||
let number = " ".to_string()
|
||||
+ numbering
|
||||
.iter()
|
||||
.map(|n| n.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(".")
|
||||
.as_str();
|
||||
number
|
||||
|
||||
let mut result = String::new();
|
||||
for num in numbering.iter()
|
||||
{
|
||||
result = result + num.to_string().as_str() + ".";
|
||||
}
|
||||
result += " ";
|
||||
|
||||
result
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
@ -71,8 +72,10 @@ impl Element for Section {
|
|||
|
||||
let refname = Compiler::refname(compiler.target(), self.title.as_str());
|
||||
let link = format!(
|
||||
"<a class=\"section-link\" href=\"#{refname}\">{}</a>",
|
||||
Compiler::sanitize(compiler.target(), self.style.link.as_str())
|
||||
"{}<a class=\"section-link\" href=\"#{refname}\">{}</a>{}",
|
||||
Compiler::sanitize(compiler.target(), self.style.link[0].as_str()),
|
||||
Compiler::sanitize(compiler.target(), self.style.link[1].as_str()),
|
||||
Compiler::sanitize(compiler.target(), self.style.link[2].as_str())
|
||||
);
|
||||
|
||||
if self.style.link_pos == SectionLinkPos::After {
|
||||
|
@ -123,7 +126,7 @@ impl ReferenceableElement for Section {
|
|||
);
|
||||
|
||||
Ok(format!(
|
||||
"<a class=\"section-ref\" href=\"#{}\">{caption}</a>",
|
||||
"<a class=\"section-reference\" href=\"#{}\">{caption}</a>",
|
||||
Compiler::refname(compiler.target(), self.title.as_str())
|
||||
))
|
||||
}
|
||||
|
@ -390,14 +393,14 @@ mod section_style {
|
|||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SectionStyle {
|
||||
pub link_pos: SectionLinkPos,
|
||||
pub link: String,
|
||||
pub link: [String; 3],
|
||||
}
|
||||
|
||||
impl Default for SectionStyle {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
link_pos: SectionLinkPos::After,
|
||||
link: "🔗".to_string(),
|
||||
link_pos: SectionLinkPos::Before,
|
||||
link: ["".into(), "🔗".into(), " ".into()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{cell::{RefCell, RefMut}, collections::HashMap, rc::Rc};
|
||||
|
||||
use crate::{document::{document::Document, element::Element}, lua::kernel::{Kernel, KernelHolder}, parser::{parser::{Parser, ReportColors}, rule::Rule, source::{Cursor, Source}, state::StateHolder}};
|
||||
use crate::{document::{document::Document, element::Element, style::{ElementStyle, StyleHolder}}, lua::kernel::{Kernel, KernelHolder}, parser::{parser::{Parser, ReportColors}, rule::Rule, source::{Cursor, Source}, state::StateHolder}};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LineCursor
|
||||
|
@ -146,3 +146,13 @@ impl KernelHolder for LsParser
|
|||
self.get_kernel(name.as_str()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl StyleHolder for LsParser {
|
||||
fn styles(&self) -> std::cell::Ref<'_, HashMap<String, Rc<dyn ElementStyle>>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn styles_mut(&self) -> RefMut<'_, HashMap<String, Rc<dyn ElementStyle>>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue