diff --git a/archive/styles/alphanumeric.cbor b/archive/styles/alphanumeric.cbor index ff7d6a1b..4ebe8a77 100644 --- a/archive/styles/alphanumeric.cbor +++ b/archive/styles/alphanumeric.cbor @@ -1 +1 @@ -¿dinfoªfauthor‚¢dnamekMartin Haugeemailumartin.haug@typst.app¢dnamenLaurenz Mädjeeemailxlaurenz.maedje@typst.appkcontributor€hcategory¡p@citation-formatelabelefield€bidx!http://typst.org/csl/alphanumericdissn€dlink€frights¡e$textqMIT OR Apache-2.0gsummary¡f$valuevAlphanumeric citationsetitle¡f$valuelAlphanumerich@versionc1.0hcitation¿dsort¡ckey‚¢i@variablefauthore@sortiascending¢i@variablefissuede@sortiascendingflayout¤f$value¡dtext¿i@variablencitation-labele@formdlongg@quotesôn@strip-periodsôÿg@prefixa[g@suffixa]j@delimiterb, x@disambiguate-add-givennameôx@givenname-disambiguation-rulegby-citew@disambiguate-add-namesôx@disambiguate-add-year-suffixôi@collapseocitation-numberx@after-collapse-delimiterb; s@near-note-distanceÿf@classgin-textw@initialize-with-hyphenõx@demote-non-dropping-particlepdisplay-and-sortemacro€flocale€ÿ \ No newline at end of file +¿dinfoªfauthor‚¢dnamekMartin Haugeemailumartin.haug@typst.app¢dnamenLaurenz Mädjeeemailxlaurenz.maedje@typst.appkcontributor€hcategory¡p@citation-formatelabelefield€bidx!http://typst.org/csl/alphanumericdissn€dlink€frights¡e$textqMIT OR Apache-2.0gsummary¡f$valuevAlphanumeric citationsetitle¡f$valuelAlphanumerich@versionc1.0hcitation¿dsort¡ckey‚¢i@variablefauthore@sortiascending¢i@variablefissuede@sortiascendingflayout¤f$value‚¡dtext¿i@variablencitation-labele@formdlongg@quotesôn@strip-periodsôÿ¡dtext¿i@variablekyear-suffixe@formdlongg@quotesôn@strip-periodsôÿg@prefixa[g@suffixa]j@delimiterb, x@disambiguate-add-givennameôx@givenname-disambiguation-rulegby-citew@disambiguate-add-namesôx@disambiguate-add-year-suffixõi@collapseocitation-numberx@after-collapse-delimiterb; s@near-note-distanceÿf@classgin-textw@initialize-with-hyphenõx@demote-non-dropping-particlepdisplay-and-sortemacro€flocale€ÿ \ No newline at end of file diff --git a/src/csl/elem.rs b/src/csl/elem.rs index 5429f636..36b9d38a 100644 --- a/src/csl/elem.rs +++ b/src/csl/elem.rs @@ -141,6 +141,9 @@ pub enum ElemMeta { Name(NameVariable, usize), /// The entry corresponds to a citation item. Entry(usize), + /// The element is the output of `cs:text` with a `variable` set to + /// `citation-label`. + CitationLabel, } /// A container for element children with useful methods. @@ -165,20 +168,18 @@ impl ElemChildren { /// Retrieve a reference to the first child with a matching meta by /// DFS. - pub fn get_meta(&self, meta: ElemMeta) -> Option<&Elem> { - for child in &self.0 { - match child { - ElemChild::Elem(e) if e.meta == Some(meta) => return Some(e), - ElemChild::Elem(e) => { - if let Some(e) = e.children.get_meta(meta) { - return Some(e); - } - } - _ => {} - } - } - - None + pub fn find_meta(&self, meta: ElemMeta) -> Option<&Elem> { + self.find_elem_by(&|e| e.meta == Some(meta)) + } + + /// Retrieve a mutable reference to the first child matching the predicate + /// by DFS. + pub fn find_elem_by bool>(&self, f: &F) -> Option<&Elem> { + self.0.iter().find_map(|child| match child { + ElemChild::Elem(e) if f(e) => Some(e), + ElemChild::Elem(e) => e.children.find_elem_by(f), + _ => None, + }) } /// Remove the first child with any meta by DFS. diff --git a/src/csl/mod.rs b/src/csl/mod.rs index c6005386..b8649c23 100644 --- a/src/csl/mod.rs +++ b/src/csl/mod.rs @@ -296,7 +296,7 @@ impl<'a, T: EntryLike + Hash + PartialEq + Eq + Debug> BibliographyDriver<'a, T> let Some(name_elem) = cite.items[i] .rendered - .get_meta(ElemMeta::Names) + .find_meta(ElemMeta::Names) .map(|e| format!("{:?}", e)) else { continue; @@ -775,19 +775,32 @@ fn disambiguate_year_suffix( T: EntryLike + PartialEq, F: FnMut(&T, DisambiguateState), { - if renders - .iter() - .flat_map(|r| r.items.iter()) - .any(|i| i.rendered.get_meta(ElemMeta::Date).is_some()) - && group.iter().any(|&(cite_idx, item_idx)| { - renders[cite_idx].request.style.citation.disambiguate_add_year_suffix - && renders[cite_idx].items[item_idx] - .cite_props - .speculative - .disambiguation - .may_disambiguate_with_year_suffix() - }) - { + if renders.iter().flat_map(|r| r.items.iter()).any(|i| { + let entry_has_date = i + .entry + .resolve_date_variable(DateVariable::Issued) + .or_else(|| i.entry.resolve_date_variable(DateVariable::Accessed)) + .or_else(|| i.entry.resolve_date_variable(DateVariable::AvailableDate)) + .or_else(|| i.entry.resolve_date_variable(DateVariable::EventDate)) + .or_else(|| i.entry.resolve_date_variable(DateVariable::Submitted)) + .or_else(|| i.entry.resolve_date_variable(DateVariable::OriginalDate)) + .is_some(); + + i.rendered + .find_elem_by(&|e| { + // The citation label will contain the date if there is one. + e.meta == Some(ElemMeta::Date) + || (entry_has_date && e.meta == Some(ElemMeta::CitationLabel)) + }) + .is_some() + }) && group.iter().any(|&(cite_idx, item_idx)| { + renders[cite_idx].request.style.citation.disambiguate_add_year_suffix + && renders[cite_idx].items[item_idx] + .cite_props + .speculative + .disambiguation + .may_disambiguate_with_year_suffix() + }) { let mut entries = Vec::new(); for &(cite_idx, item_idx) in group.iter() { let item = &renders[cite_idx].items[item_idx]; @@ -922,7 +935,7 @@ fn collapse_items<'a, T: EntryLike>(cite: &mut SpeculativeCiteRender<'a, '_, T>) // cannot be mutably borrowed below otherwise. let item = &cite.items[i]; if item.hidden - || item.rendered.get_meta(ElemMeta::CitationNumber).is_none() + || item.rendered.find_meta(ElemMeta::CitationNumber).is_none() { end_range(&mut cite.items, &mut range_start, &mut just_collapsed); continue; @@ -2922,4 +2935,57 @@ mod tests { assert_eq!(yield_year(-1, true), "2BC"); assert_eq!(yield_year(1, true), "1AD"); } + + #[cfg(feature = "archive")] + fn test_alphanumeric_disambiguation() { + let bibtex = r#"@article{chenTransMorphTransformerUnsupervised2021, + title = {{{TransMorph}}: {{Transformer}} for Unsupervised Medical Image Registration}, + author = {Chen, Junyu and Frey, Eric C. and He, Yufan and Segars, William P. and Li, Ye and Du, Yong}, + date = {2021}, +} + +@article{chenViTVNetVisionTransformer2021, + title = {{{ViT-V-Net}}: {{Vision Transformer}} for {{Unsupervised Volumetric Medical Image Registration}}}, + author = {Chen, Junyu and He, Yufan and Frey, Eric C. and Li, Ye and Du, Yong}, + date = {2021}, +}"#; + + let library = crate::io::from_biblatex_str(bibtex).unwrap(); + let alphanumeric = archive::ArchivedStyle::Alphanumeric.get(); + let citationberg::Style::Independent(alphanumeric) = alphanumeric else { + unreachable!() + }; + + let mut driver = BibliographyDriver::new(); + for entry in library.iter() { + driver.citation(CitationRequest::new( + vec![CitationItem::with_entry(entry)], + &alphanumeric, + None, + &[], + None, + )); + } + + let finished = driver.finish(BibliographyRequest { + style: &alphanumeric, + locale: None, + locale_files: &[], + }); + + let mut c1 = String::new(); + let mut c2 = String::new(); + + finished.citations[0] + .citation + .write_buf(&mut c1, BufWriteFormat::Plain) + .unwrap(); + finished.citations[1] + .citation + .write_buf(&mut c2, BufWriteFormat::Plain) + .unwrap(); + + assert_eq!(c1, "[Che+21a]"); + assert_eq!(c2, "[Che+21b]"); + } } diff --git a/src/csl/rendering/mod.rs b/src/csl/rendering/mod.rs index 29d58cb5..526857f0 100644 --- a/src/csl/rendering/mod.rs +++ b/src/csl/rendering/mod.rs @@ -126,6 +126,11 @@ impl RenderCsl for citationberg::Text { { Some(ElemMeta::CitationNumber) } + TextTarget::Variable { var, .. } + if var == StandardVariable::CitationLabel.into() => + { + Some(ElemMeta::CitationLabel) + } TextTarget::Variable { .. } => Some(ElemMeta::Text), _ => None, }, diff --git a/styles/alphanumeric.csl b/styles/alphanumeric.csl index ea29af6b..5461b148 100644 --- a/styles/alphanumeric.csl +++ b/styles/alphanumeric.csl @@ -15,13 +15,15 @@ MIT OR Apache-2.0 Alphanumeric citations - + + \ No newline at end of file