From cc7bc7169c168d43a25316c4527ae6f252dbd2bb Mon Sep 17 00:00:00 2001
From: ef3d0c3e <ef3d0c3e@pundalik.org>
Date: Sun, 4 Aug 2024 08:32:15 +0200
Subject: [PATCH] Better sorting
---
src/compiler/navigation.rs | 98 ++++++++++++++++++--------------------
src/elements/section.rs | 37 ++++++++++++++
src/main.rs | 1 -
3 files changed, 84 insertions(+), 52 deletions(-)
diff --git a/src/compiler/navigation.rs b/src/compiler/navigation.rs
index 7d92f8d..becffaa 100644
--- a/src/compiler/navigation.rs
+++ b/src/compiler/navigation.rs
@@ -76,34 +76,28 @@ 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;
+ left: &(String, String, Option<String>),
+ right: &(String, String, Option<String>),
+ ) -> std::cmp::Ordering {
+ match (&left.2, &right.2) {
+ (Some(_), Some(_)) => left.0.cmp(&right.0),
+ (Some(lp), None) => {
+ if &right.0 == lp {
+ std::cmp::Ordering::Greater
+ } else {
+ left.0.cmp(&right.0)
}
}
- }
-
- // 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;
+ (None, Some(rp)) => {
+ if &left.0 == rp {
+ std::cmp::Ordering::Less
+ } else {
+ left.0.cmp(&right.0)
+ }
}
-
- insert_at += 1;
+ (None, None) => left.0.cmp(&right.0),
}
-
- insert_at
}
}
@@ -196,47 +190,49 @@ pub fn create_navigation(docs: &Vec<CompiledDocument>) -> Result<NavEntry, Strin
}
all_paths.insert(path.clone(), title.clone());
- pent.entries.insert(
- NavEntry::sort_entry(title, &previous, &pent.entries),
- (title.clone(), path.clone(), previous),
- );
+ pent.entries.push((title.clone(), path.clone(), previous));
}
+ // Sort entries
+ fn sort_entries(nav: &mut NavEntry) {
+ nav.entries
+ .sort_unstable_by(|l, r| NavEntry::sort_entry(l, r));
+
+ for (_, child) in &mut nav.children {
+ sort_entries(child);
+ }
+ }
+ sort_entries(&mut nav);
+
Ok(nav)
}
#[cfg(test)]
mod tests {
+ use rand::rngs::OsRng;
+ use rand::RngCore;
+
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())),
+ let mut entries: Vec<(String, String, Option<String>)> = vec![
+ ("Index".into(), "".into(), None),
+ ("AB".into(), "".into(), Some("Index".into())),
+ ("Getting Started".into(), "".into(), Some("Index".into())),
+ ("Sections".into(), "".into(), Some("Getting Started".into())),
+ ("Style".into(), "".into(), Some("Getting Started".into())),
];
+ let mut shuffled = entries.clone();
+ for _ in 0..10 {
+ for i in 0..5 {
+ let pos = OsRng.next_u64() % entries.len() as u64;
+ shuffled.swap(i, pos as usize);
+ }
- 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);
+ shuffled.sort_by(|l, r| NavEntry::sort_entry(l, r));
- 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
- );
+ assert_eq!(shuffled, entries);
+ }
}
}
diff --git a/src/elements/section.rs b/src/elements/section.rs
index 1116282..d7f9eab 100644
--- a/src/elements/section.rs
+++ b/src/elements/section.rs
@@ -407,3 +407,40 @@ mod section_style {
impl_elementstyle!(SectionStyle, STYLE_KEY);
}
+
+#[cfg(test)]
+mod tests
+{
+ use crate::{parser::{langparser::LangParser, source::SourceFile}, validate_document};
+
+use super::*;
+
+ #[test]
+ fn parser()
+ {
+ let source = Rc::new(SourceFile::with_content(
+ "".to_string(),
+ r#"
+# 1
+##+ 2
+###* 3
+####+* 4
+#####*+ 5
+######{refname} 6
+ "#
+ .to_string(),
+ None,
+ ));
+ let parser = LangParser::default();
+ let doc = parser.parse(source, None);
+
+ validate_document!(doc.content().borrow(), 0,
+ Section { depth == 1, title == "1" };
+ Section { depth == 2, title == "2", kind == section_kind::NO_TOC };
+ Section { depth == 3, title == "3", kind == section_kind::NO_NUMBER };
+ Section { depth == 4, title == "4", kind == section_kind::NO_NUMBER | section_kind::NO_TOC };
+ Section { depth == 5, title == "5", kind == section_kind::NO_NUMBER | section_kind::NO_TOC };
+ Section { depth == 6, title == "6", reference == Some("refname".to_string()) };
+ );
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index d820a0d..be36b5c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,3 @@
-#![feature(char_indices_offset)]
mod cache;
mod compiler;
mod document;