1""" 2.. autofunction:: sphinxcontrib.bibtex.style.template.join(\ 3 sep='', sep2=None, last_sep=None, other=None) 4 5.. autofunction:: sphinxcontrib.bibtex.style.template.sentence(\ 6 capfirst=False, capitalize=False, add_period=True, \ 7 sep=', ', sep2=None, last_sep=None, other=None) 8 9.. autofunction:: sphinxcontrib.bibtex.style.template.names(\ 10 role, sep='', sep2=None, last_sep=None, other=None) 11 12.. autofunction:: sphinxcontrib.bibtex.style.template.entry_label() 13 14.. autofunction:: sphinxcontrib.bibtex.style.template.reference() 15""" 16 17from pybtex.richtext import Text 18from pybtex.style.template import ( 19 Node, _format_list, FieldIsMissing, field, first_of, optional, tag 20) 21from typing import TYPE_CHECKING, Dict, Any, cast, Type 22 23from sphinxcontrib.bibtex.richtext import BaseReferenceText 24 25if TYPE_CHECKING: 26 from pybtex.richtext import BaseText 27 from pybtex.style import FormattedEntry 28 29 30# extended from pybtex: also copies the docstring into the wrapped object 31def node(f): 32 n = Node(f.__name__, f) 33 n.__doc__ = f.__doc__ 34 return n 35 36 37# copied from pybtex join but extended to allow "et al" formatting 38@node 39def join(children, data, sep='', sep2=None, last_sep=None, other=None): 40 """Join text fragments together.""" 41 42 if sep2 is None: 43 sep2 = sep 44 if last_sep is None: 45 last_sep = sep 46 parts = [part for part in _format_list(children, data) if part] 47 if len(parts) <= 1: 48 return Text(*parts) 49 elif len(parts) == 2: 50 return Text(sep2).join(parts) 51 elif other is None: 52 return Text(last_sep).join([Text(sep).join(parts[:-1]), parts[-1]]) 53 else: 54 return Text(parts[0], other) 55 56 57# copied from pybtex names but using the new join 58@node 59def sentence(children, data, capfirst=False, capitalize=False, add_period=True, 60 sep=', ', sep2=None, last_sep=None, other=None): 61 """Join text fragments, capitalize the first letter, 62 and add a period to the end. 63 """ 64 text = join(sep=sep, sep2=sep2, last_sep=last_sep, other=other)[ 65 children 66 ].format_data(data) 67 if capfirst: 68 text = text.capfirst() 69 if capitalize: 70 text = text.capitalize() 71 if add_period: 72 text = text.add_period() 73 return text 74 75 76# copied from pybtex names but using the new join allowing "et al" formatting 77@node 78def names(children, data, role, **kwargs): 79 """Return formatted names.""" 80 assert not children 81 try: 82 persons = data['entry'].persons[role] 83 except KeyError: 84 raise FieldIsMissing(role, data['entry']) 85 style = data['style'] 86 formatted_names = [ 87 style.person.style_plugin.format(person, style.person.abbreviate) 88 for person in persons] 89 return join(**kwargs)[formatted_names].format_data(data) 90 91 92@node 93def entry_label(children, data) -> "BaseText": 94 """Node for inserting the label of a formatted entry.""" 95 assert not children 96 entry = cast("FormattedEntry", data['formatted_entry']) 97 return Text(entry.label) 98 99 100@node 101def reference(children, data: Dict[str, Any]): 102 """Node for inserting a citation reference. The children of the node 103 comprise the content of the reference, and any referencing information 104 is stored in the *reference_info* key of the *data*. 105 The data must also contain a *style* key pointing to the corresponding 106 :class:`~sphinxcontrib.bibtex.style.referencing.BaseReferenceStyle`. 107 """ 108 parts = _format_list(children, data) 109 info = data['reference_info'] 110 reference_text_class: Type[BaseReferenceText] \ 111 = data['reference_text_class'] 112 return reference_text_class(info, *parts) 113 114 115@node 116def footnote_reference(children, data: Dict[str, Any]): 117 """Node for inserting a footnote reference. The children of the node 118 comprise the content of the reference, and any referencing information 119 is stored in the *reference_info* key of the *data*. 120 The data must also contain a *style* key pointing to the corresponding 121 :class:`~sphinxcontrib.bibtex.style.referencing.BaseReferenceStyle`. 122 """ 123 assert not children 124 info = data['reference_info'] 125 reference_text_class: Type[BaseReferenceText] \ 126 = data['reference_text_class'] 127 # we need to give the footnote text some fake content 128 # otherwise pybtex richtext engine will mess things up 129 return reference_text_class(info, '#') 130 131 132@node 133def year(children, data: Dict[str, Any]) -> "BaseText": 134 assert not children 135 return first_of[optional[field('year')], 'n.d.'].format_data(data) 136 137 138@node 139def author_or_editor_or_title(children, data, **kwargs): 140 assert not children 141 return first_of[ 142 optional[names('author', **kwargs)], 143 optional[names('editor', **kwargs)], 144 tag('em')[field('title')]].format_data(data) 145