Skip to content

Commit

Permalink
Fix sorting citation by citation number (#168)
Browse files Browse the repository at this point in the history
* Fix sorting citation by citation number

We need to defer sorting the citations until the citation numbers are
assigned.

* Add local test for sorting by citation number

Citation number sorting is coverd in the test suite only by CITATIONS
tests which we do not support. This commit adds support for local test
cases and adapts one such test to use CITATION-ITEMS.

* use generics for citation number

* move local tests to tests/local

---------

Co-authored-by: PgBiel <9021226+PgBiel@users.noreply.github.com>
  • Loading branch information
lluchs and PgBiel authored Aug 6, 2024
1 parent af287f8 commit f70041f
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 8 deletions.
24 changes: 17 additions & 7 deletions src/csl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,17 @@ impl<'a, T: EntryLike> BibliographyDriver<'a, T> {

/// Create a new citation with the given items.
pub fn citation(&mut self, mut req: CitationRequest<'a, T>) {
let style = req.style();

for (i, item) in req.items.iter_mut().enumerate() {
item.initial_idx = i;
}
style.sort(&mut req.items, style.csl.citation.sort.as_ref(), req.locale.as_ref());
self.citations.push(req);
}
}

/// Implementations for finishing the bibliography.
impl<'a, T: EntryLike + Hash + PartialEq + Eq + Debug> BibliographyDriver<'a, T> {
/// Render the bibliography.
pub fn finish(self, request: BibliographyRequest<'_>) -> Rendered {
pub fn finish(mut self, request: BibliographyRequest<'_>) -> Rendered {
// 1. Assign citation numbers by bibliography ordering or by citation
// order and render them a first time without their locators.
let bib_style = request.style();
Expand All @@ -115,6 +112,7 @@ impl<'a, T: EntryLike + Hash + PartialEq + Eq + Debug> BibliographyDriver<'a, T>
&mut entries,
bib_style.csl.bibliography.as_ref().and_then(|b| b.sort.as_ref()),
request.locale.as_ref(),
|_| 0,
);
let citation_number = |item: &T| {
entries.iter().position(|e| e.entry == item).expect("entry not found")
Expand All @@ -124,10 +122,17 @@ impl<'a, T: EntryLike + Hash + PartialEq + Eq + Debug> BibliographyDriver<'a, T>
let mut res: Vec<SpeculativeCiteRender<T>> = Vec::new();
let mut last_cite: Option<&CitationItem<T>> = None;

for citation in &self.citations {
let items = &citation.items;
for citation in &mut self.citations {
let style = citation.style();

style.sort(
&mut citation.items,
style.csl.citation.sort.as_ref(),
citation.locale.as_ref(),
&citation_number,
);

let items = &citation.items;
let mut renders: Vec<SpeculativeItemRender<'_, T>> = Vec::new();

for item in items.iter() {
Expand Down Expand Up @@ -516,7 +521,12 @@ pub fn standalone_citation<T: EntryLike>(
mut req: CitationRequest<'_, T>,
) -> ElemChildren {
let style = req.style();
style.sort(&mut req.items, style.csl.citation.sort.as_ref(), req.locale.as_ref());
style.sort(
&mut req.items,
style.csl.citation.sort.as_ref(),
req.locale.as_ref(),
|_| 0,
);
let mut res = vec![];
let mut all_hidden = true;
for item in req.items {
Expand Down
10 changes: 9 additions & 1 deletion src/csl/sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,20 @@ impl<'a> StyleContext<'a> {
cites: &mut [CitationItem<T>],
sort: Option<&Sort>,
term_locale: Option<&LocaleCode>,
citation_number: impl Fn(&T) -> usize,
) {
if let Some(sort) = sort {
cites.sort_by(|a, b| {
let mut ordering = Ordering::Equal;
for key in &sort.keys {
ordering = self.cmp_entries(a, 0, b, 0, key, term_locale);
ordering = self.cmp_entries(
a,
citation_number(a.entry),
b,
citation_number(b.entry),
key,
term_locale,
);
if ordering != Ordering::Equal {
break;
}
Expand Down
12 changes: 12 additions & 0 deletions tests/citeproc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,18 @@ fn test_single_file() {
assert!(test_file(case, &locales, || path.display()));
}

#[test]
fn test_local_files() {
let locales = locales();
let test_path = PathBuf::from("tests/local");

for path in iter_files_with_name(&test_path, "txt", |_| true) {
let case = build_case(&std::fs::read_to_string(&path).unwrap());
assert!(can_test(&case, || path.display(), true));
assert!(test_file(case, &locales, || path.display()));
}
}

fn build_case(s: &str) -> TestCase {
let mut s = Scanner::new(s);
let mut builder = TestCaseBuilder::new();
Expand Down
98 changes: 98 additions & 0 deletions tests/local/collapse_CitationNumberRangesSort.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
>>===== MODE =====>>
citation
<<===== MODE =====<<

Simplified from collapse_CitationNumberRangesInsert.txt


>>===== RESULT =====>>
[1]–[4]
[1]–[4]
<<===== RESULT =====<<

>>===== CITATION-ITEMS =====>>
[
[
{
"id": "ITEM-1"
},
{
"id": "ITEM-2"
},
{
"id": "ITEM-3"
},
{
"id": "ITEM-4"
}
],
[
{
"id": "ITEM-2"
},
{
"id": "ITEM-1"
},
{
"id": "ITEM-4"
},
{
"id": "ITEM-3"
}
]
]
<<===== CITATION-ITEMS =====<<


>>===== CSL =====>>
<style
xmlns="http://purl.org/net/xbiblio/csl"
class="note"
version="1.0">
<info>
<id />
<title />
<updated>2009-08-10T04:49:00+09:00</updated>
</info>
<citation
collapse="citation-number">
<sort>
<key variable="citation-number" />
</sort>
<layout delimiter=", ">
<text prefix="[" suffix="]" variable="citation-number" />
</layout>
</citation>
</style>
<<===== CSL =====<<


>>===== INPUT =====>>
[
{
"id": "ITEM-1",
"title": "Paper 1",
"type": "book"
},
{
"id": "ITEM-2",
"title": "Paper 2",
"type": "book"
},
{
"id": "ITEM-3",
"title": "Paper 3",
"type": "book"
},
{
"id": "ITEM-4",
"title": "Paper 4",
"type": "book"
}
]
<<===== INPUT =====<<


>>===== VERSION =====>>
1.0
<<===== VERSION =====<<

0 comments on commit f70041f

Please sign in to comment.