@@ -212,7 +212,7 @@ impl<'a, T: EntryLike + Hash + PartialEq + Eq + Debug> BibliographyDriver<'a, T>
212212 //
213213 // If we have set the disambiguation state for an item, we need to set
214214 // the same state for all entries referencing that item.
215- for _ in 0 ..6 {
215+ for _ in 0 ..16 {
216216 let ambiguous = find_ambiguous_sets ( & res) ;
217217 if ambiguous. is_empty ( ) {
218218 break ;
@@ -296,7 +296,7 @@ impl<'a, T: EntryLike + Hash + PartialEq + Eq + Debug> BibliographyDriver<'a, T>
296296
297297 let Some ( name_elem) = cite. items [ i]
298298 . rendered
299- . get_meta ( ElemMeta :: Names )
299+ . find_meta ( ElemMeta :: Names )
300300 . map ( |e| format ! ( "{:?}" , e) )
301301 else {
302302 continue ;
@@ -639,19 +639,9 @@ fn date_replacement<T: EntryLike>(
639639
640640 ElemChildren ( vec ! [ ElemChild :: Text ( Formatted {
641641 text: if let Some ( date) = date {
642- format!(
643- "{}{}" ,
644- if date. year > 0 { date. year } else { date. year. abs( ) + 1 } ,
645- if date. year < 1000 {
646- if date. year < 0 {
647- "BC"
648- } else {
649- "AD"
650- }
651- } else {
652- ""
653- }
654- )
642+ let mut s = String :: with_capacity( 4 ) ;
643+ write_year( date. year, false , & mut s) . unwrap( ) ;
644+ s
655645 } else if let Some ( no_date) = ctx
656646 . ctx( entry, cite_props. clone( ) , locale, term_locale, false )
657647 . term( Term :: Other ( OtherTerm :: NoDate ) , TermForm :: default ( ) , false )
@@ -664,6 +654,33 @@ fn date_replacement<T: EntryLike>(
664654 } ) ] )
665655}
666656
657+ pub fn write_year < W : std:: fmt:: Write > (
658+ year : i32 ,
659+ short : bool ,
660+ w : & mut W ,
661+ ) -> std:: fmt:: Result {
662+ if short && year >= 1000 {
663+ return write ! ( w, "{:02}" , year % 100 ) ;
664+ }
665+
666+ write ! (
667+ w,
668+ "{}{}" ,
669+ if year > 0 { year } else { year. abs( ) + 1 } ,
670+ if year < 1000 {
671+ if year <= 0 {
672+ "BC"
673+ } else {
674+ // AD is used as a postfix, see
675+ // https://docs.citationstyles.org/en/stable/specification.html?#ad-and-bc
676+ "AD"
677+ }
678+ } else {
679+ ""
680+ }
681+ )
682+ }
683+
667684fn last_purpose_render < T : EntryLike + Debug > (
668685 ctx : & StyleContext < ' _ > ,
669686 item : & SpeculativeItemRender < T > ,
@@ -764,19 +781,32 @@ fn disambiguate_year_suffix<F, T>(
764781 T : EntryLike + PartialEq ,
765782 F : FnMut ( & T , DisambiguateState ) ,
766783{
767- if renders
768- . iter ( )
769- . flat_map ( |r| r. items . iter ( ) )
770- . any ( |i| i. rendered . get_meta ( ElemMeta :: Date ) . is_some ( ) )
771- && group. iter ( ) . any ( |& ( cite_idx, item_idx) | {
772- renders[ cite_idx] . request . style . citation . disambiguate_add_year_suffix
773- && renders[ cite_idx] . items [ item_idx]
774- . cite_props
775- . speculative
776- . disambiguation
777- . may_disambiguate_with_year_suffix ( )
778- } )
779- {
784+ if renders. iter ( ) . flat_map ( |r| r. items . iter ( ) ) . any ( |i| {
785+ let entry_has_date = i
786+ . entry
787+ . resolve_date_variable ( DateVariable :: Issued )
788+ . or_else ( || i. entry . resolve_date_variable ( DateVariable :: Accessed ) )
789+ . or_else ( || i. entry . resolve_date_variable ( DateVariable :: AvailableDate ) )
790+ . or_else ( || i. entry . resolve_date_variable ( DateVariable :: EventDate ) )
791+ . or_else ( || i. entry . resolve_date_variable ( DateVariable :: Submitted ) )
792+ . or_else ( || i. entry . resolve_date_variable ( DateVariable :: OriginalDate ) )
793+ . is_some ( ) ;
794+
795+ i. rendered
796+ . find_elem_by ( & |e| {
797+ // The citation label will contain the date if there is one.
798+ e. meta == Some ( ElemMeta :: Date )
799+ || ( entry_has_date && e. meta == Some ( ElemMeta :: CitationLabel ) )
800+ } )
801+ . is_some ( )
802+ } ) && group. iter ( ) . any ( |& ( cite_idx, item_idx) | {
803+ renders[ cite_idx] . request . style . citation . disambiguate_add_year_suffix
804+ && renders[ cite_idx] . items [ item_idx]
805+ . cite_props
806+ . speculative
807+ . disambiguation
808+ . may_disambiguate_with_year_suffix ( )
809+ } ) {
780810 let mut entries = Vec :: new ( ) ;
781811 for & ( cite_idx, item_idx) in group. iter ( ) {
782812 let item = & renders[ cite_idx] . items [ item_idx] ;
@@ -911,7 +941,7 @@ fn collapse_items<'a, T: EntryLike>(cite: &mut SpeculativeCiteRender<'a, '_, T>)
911941 // cannot be mutably borrowed below otherwise.
912942 let item = & cite. items [ i] ;
913943 if item. hidden
914- || item. rendered . get_meta ( ElemMeta :: CitationNumber ) . is_none ( )
944+ || item. rendered . find_meta ( ElemMeta :: CitationNumber ) . is_none ( )
915945 {
916946 end_range ( & mut cite. items , & mut range_start, & mut just_collapsed) ;
917947 continue ;
@@ -3096,4 +3126,76 @@ mod tests {
30963126 // }
30973127 }
30983128 }
3129+
3130+ #[ test]
3131+ fn low_year_test ( ) {
3132+ let yield_year = |year, short| {
3133+ let mut s = String :: new ( ) ;
3134+ write_year ( year, short, & mut s) . unwrap ( ) ;
3135+ s
3136+ } ;
3137+
3138+ assert_eq ! ( yield_year( 2021 , false ) , "2021" ) ;
3139+ assert_eq ! ( yield_year( 2021 , true ) , "21" ) ;
3140+ assert_eq ! ( yield_year( 0 , false ) , "1BC" ) ;
3141+ assert_eq ! ( yield_year( -1 , false ) , "2BC" ) ;
3142+ assert_eq ! ( yield_year( 1 , false ) , "1AD" ) ;
3143+ assert_eq ! ( yield_year( 0 , true ) , "1BC" ) ;
3144+ assert_eq ! ( yield_year( -1 , true ) , "2BC" ) ;
3145+ assert_eq ! ( yield_year( 1 , true ) , "1AD" ) ;
3146+ }
3147+
3148+ #[ test]
3149+ #[ cfg( feature = "archive" ) ]
3150+ fn test_alphanumeric_disambiguation ( ) {
3151+ let bibtex = r#"@article{chenTransMorphTransformerUnsupervised2021,
3152+ title = {{{TransMorph}}: {{Transformer}} for Unsupervised Medical Image Registration},
3153+ author = {Chen, Junyu and Frey, Eric C. and He, Yufan and Segars, William P. and Li, Ye and Du, Yong},
3154+ date = {2021},
3155+ }
3156+
3157+ @article{chenViTVNetVisionTransformer2021,
3158+ title = {{{ViT-V-Net}}: {{Vision Transformer}} for {{Unsupervised Volumetric Medical Image Registration}}},
3159+ author = {Chen, Junyu and He, Yufan and Frey, Eric C. and Li, Ye and Du, Yong},
3160+ date = {2021},
3161+ }"# ;
3162+
3163+ let library = crate :: io:: from_biblatex_str ( bibtex) . unwrap ( ) ;
3164+ let alphanumeric = archive:: ArchivedStyle :: Alphanumeric . get ( ) ;
3165+ let citationberg:: Style :: Independent ( alphanumeric) = alphanumeric else {
3166+ unreachable ! ( )
3167+ } ;
3168+
3169+ let mut driver = BibliographyDriver :: new ( ) ;
3170+ for entry in library. iter ( ) {
3171+ driver. citation ( CitationRequest :: new (
3172+ vec ! [ CitationItem :: with_entry( entry) ] ,
3173+ & alphanumeric,
3174+ None ,
3175+ & [ ] ,
3176+ None ,
3177+ ) ) ;
3178+ }
3179+
3180+ let finished = driver. finish ( BibliographyRequest {
3181+ style : & alphanumeric,
3182+ locale : None ,
3183+ locale_files : & [ ] ,
3184+ } ) ;
3185+
3186+ let mut c1 = String :: new ( ) ;
3187+ let mut c2 = String :: new ( ) ;
3188+
3189+ finished. citations [ 0 ]
3190+ . citation
3191+ . write_buf ( & mut c1, BufWriteFormat :: Plain )
3192+ . unwrap ( ) ;
3193+ finished. citations [ 1 ]
3194+ . citation
3195+ . write_buf ( & mut c2, BufWriteFormat :: Plain )
3196+ . unwrap ( ) ;
3197+
3198+ assert_eq ! ( c1, "[Che+21a]" ) ;
3199+ assert_eq ! ( c2, "[Che+21b]" ) ;
3200+ }
30993201}
0 commit comments