Skip to content

Commit

Permalink
Merge branch 'main' into page-range
Browse files Browse the repository at this point in the history
  • Loading branch information
DerDrodt committed Aug 19, 2024
2 parents f269f09 + 954962e commit 670351e
Show file tree
Hide file tree
Showing 8 changed files with 330 additions and 35 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ csl-json = ["citationberg/json"]

[dependencies]
citationberg = { git = "https://github.com/typst/citationberg.git", rev = "ad52765" }
citationberg = { git = "https://github.com/typst/citationberg.git", rev = "61ca6a7fcc48365f805e521cc8bc1f8f679ff372" }
indexmap = { version = "2.0.2", features = ["serde"] }
numerals = "0.1.4"
paste = "1.0.14"
Expand Down
79 changes: 51 additions & 28 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 Expand Up @@ -846,32 +856,48 @@ fn find_ambiguous_sets<T: EntryLike + PartialEq>(
fn collapse_items<'a, T: EntryLike>(cite: &mut SpeculativeCiteRender<'a, '_, T>) {
let style = &cite.request.style;

let after_collapse_delim = style.citation.after_collapse_delimiter.as_deref();
let after_collapse_delim = style
.citation
.after_collapse_delimiter
.as_deref()
.or(style.citation.layout.delimiter.as_deref());

let group_delimiter = style.citation.cite_group_delimiter.as_deref();

match style.citation.collapse {
Some(Collapse::CitationNumber) => {
// Option with the start and end of the range.
let mut range_start: Option<(usize, usize)> = None;
let mut just_collapsed = false;

let end_range = |items: &mut [SpeculativeItemRender<'a, T>],
range_start: &mut Option<(usize, usize)>,
just_collapsed: &mut bool| {
let use_after_collapse_delim = *just_collapsed;
*just_collapsed = false;

if let &mut Some((start, end)) = range_start {
// If the previous citation range was collapsed, use the
// after-collapse delimiter before the next item.
if use_after_collapse_delim {
items[start].delim_override = after_collapse_delim;
}

let end_range =
|items: &mut [SpeculativeItemRender<'a, T>],
range_start: &mut Option<(usize, usize)>| {
if let &mut Some((start, end)) = range_start {
// There should be at least three items in the range.
if start + 1 < end {
items[end].delim_override =
after_collapse_delim.or(Some("–"));

for item in &mut items[start + 1..end] {
item.hidden = true;
}
// There should be at least three items in the range to
// collapse.
if start + 1 < end {
items[end].delim_override = Some("–");

for item in &mut items[start + 1..end] {
item.hidden = true;
}

*just_collapsed = true;
}
}

*range_start = None;
};
*range_start = None;
};

for i in 0..cite.items.len() {
let citation_number = {
Expand All @@ -881,7 +907,7 @@ fn collapse_items<'a, T: EntryLike>(cite: &mut SpeculativeCiteRender<'a, '_, T>)
if item.hidden
|| item.rendered.get_meta(ElemMeta::CitationNumber).is_none()
{
end_range(&mut cite.items, &mut range_start);
end_range(&mut cite.items, &mut range_start, &mut just_collapsed);
continue;
}

Expand All @@ -904,18 +930,15 @@ fn collapse_items<'a, T: EntryLike>(cite: &mut SpeculativeCiteRender<'a, '_, T>)
range_start = Some((start, i));
}
_ => {
end_range(&mut cite.items, &mut range_start);
end_range(&mut cite.items, &mut range_start, &mut just_collapsed);
range_start = Some((i, i));
}
}
}

end_range(&mut cite.items, &mut range_start);
end_range(&mut cite.items, &mut range_start, &mut just_collapsed);
}
Some(Collapse::Year | Collapse::YearSuffix | Collapse::YearSuffixRanged) => {
let after_collapse_delim =
after_collapse_delim.or(style.citation.layout.delimiter.as_deref());

// Index of where the current group started and the group we are
// currently in.
let mut group_idx: Option<(usize, usize)> = None;
Expand Down
4 changes: 0 additions & 4 deletions src/csl/rendering/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,6 @@ fn write_name<T: EntryLike>(

if name.given_name.is_some() {
ctx.push_str(sort_sep);
ctx.ensure_space();

let idx = ctx.push_format(first_format);
let cidx = ctx.push_case(first_case);
Expand All @@ -680,7 +679,6 @@ fn write_name<T: EntryLike>(

if let Some(suffix) = &name.suffix {
ctx.push_str(sort_sep);
ctx.ensure_space();
ctx.push_str(suffix);
}
};
Expand All @@ -704,7 +702,6 @@ fn write_name<T: EntryLike>(

if name.given_name.is_some() {
ctx.push_str(sort_sep);
ctx.ensure_space();

let idx = ctx.push_format(first_format);
let cidx = ctx.push_case(first_case);
Expand Down Expand Up @@ -735,7 +732,6 @@ fn write_name<T: EntryLike>(

if let Some(suffix) = &name.suffix {
ctx.push_str(sort_sep);
ctx.ensure_space();
ctx.push_str(suffix);
}
};
Expand Down
14 changes: 11 additions & 3 deletions src/csl/sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ impl<'a> StyleContext<'a> {
SortKey::Variable { variable: Variable::Standard(s), .. } => {
let a = InstanceContext::sort_instance(a, a_idx)
.resolve_standard_variable(LongShortForm::default(), *s)
.map(|s| s.to_string());
.map(|s| s.to_string().to_lowercase());
let b = InstanceContext::sort_instance(b, b_idx)
.resolve_standard_variable(LongShortForm::default(), *s)
.map(|s| s.to_string());
.map(|s| s.to_string().to_lowercase());

a.cmp(&b)
}
Expand Down 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
3 changes: 3 additions & 0 deletions tests/citeproc-pass.txt
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ nameattr_NameFormOnNamesInCitation
nameattr_NameFormOnStyleInCitation
nameattr_NamesDelimiterOnBibliographyInCitation
nameattr_NamesDelimiterOnNamesInCitation
nameattr_SortSeparatorOnBibliographyInCitation
nameattr_SortSeparatorOnCitationInCitation
nameattr_SortSeparatorOnNamesInCitation
nameattr_SortSeparatorOnStyleInCitation
Expand Down Expand Up @@ -291,6 +292,7 @@ position_TrueInCitation
punctuation_DateStripPeriods
punctuation_DoNotSuppressColonAfterPeriod
punctuation_NoSuppressOfPeriodBeforeSemicolon
sort_CaseInsensitiveCitation
sort_Citation
sort_CitationSecondaryKey
sort_CiteGroupDelimiter
Expand All @@ -302,6 +304,7 @@ sort_DateVariableMixedElementsDescendingB
sort_LatinUnicode
sort_LocalizedDateLimitedParts
sort_TestInheritance
sortseparator_SortSeparatorEmpty
substitute_RepeatedNamesOk
substitute_SubstituteOnlyOnceString
substitute_SubstituteOnlyOnceTerm
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
Loading

0 comments on commit 670351e

Please sign in to comment.