1#!/usr/bin/env python3
2"""
3
4See EOF for license/metadata/notes as applicable
5"""
6
7# Imports:
8from __future__ import annotations
9
10# ##-- stdlib imports
11import datetime
12import enum
13import functools as ftz
14import itertools as itz
15import logging as logmod
16import pathlib as pl
17import re
18import time
19import types
20import weakref
21from uuid import UUID, uuid1
22
23# ##-- end stdlib imports
24
25# ##-- 3rd party imports
26import bibtexparser
27import bibtexparser.model as model
28from bibtexparser.middlewares.names import NameParts
29from jgdv import Mixin, Proto
30
31# ##-- end 3rd party imports
32
33# ##-- 1st party imports
34import bibble._interface as API
35from bibble.util.middlecore import IdenBlockMiddleware
36from bibble.util.mixins import FieldMatcher_m
37from bibble.util.name_parts import NameParts_d
38
39# ##-- end 1st party imports
40
41from . import _interface as API_N
42
43# ##-- types
44# isort: off
45import abc
46import collections.abc
47from typing import TYPE_CHECKING, cast, assert_type, assert_never
48from typing import Generic, NewType
49# Protocols:
50from typing import Protocol, runtime_checkable
51# Typing Decorators:
52from typing import no_type_check, final, override, overload
53
54if TYPE_CHECKING:
55 from jgdv import Maybe, Result
56 from typing import Final
57 from typing import ClassVar, Any, LiteralString
58 from typing import Never, Self, Literal
59 from typing import TypeGuard
60 from collections.abc import Iterable, Iterator, Callable, Generator
61 from collections.abc import Sequence, Mapping, MutableMapping, Hashable
62
63 type Entry = model.Entry
64 type Field = model.Field
65 from bibtexparser import Library
66
67##--|
68
69# isort: on
70# ##-- end types
71
72##-- logging
73logging = logmod.getLogger(__name__)
74##-- end logging
75
[docs]
76@Proto(API.WriteTime_p)
77@Mixin(FieldMatcher_m)
78class NameWriter(IdenBlockMiddleware):
79 """ Transforms NameParts -> [str] -> str
80
81 on init:
82 - parts : bool = merge name parts together
83 - authors : bool = merge separate authors together
84 """
85 _whitelist = ("author", "editor", "translator")
86
87 def __init__(self, *, parts:bool, authors:bool, **kwargs):
88 super().__init__(**kwargs)
89 self._merge_parts = parts
90 self._merge_authors = authors
91 self.set_field_matchers(white=self._whitelist, black=[])
92
[docs]
93 def on_write(self):
94 Never()
95
[docs]
96 def transform_Entry(self, entry:Entry, library:Library) -> list[Entry]:
97 match self.match_on_fields(entry, library):
98 case model.Entry() as x:
99 return [x]
100 case Exception() as err:
101 return [self.make_error_block(entry, err)]
102 case x:
103 raise TypeError(type(x))
104
[docs]
105 def field_h(self, field:Field, entry:Entry) -> Result[list[Field], Exception]:
106 result = []
107 merger = self._merge_von_last_jr_first
108 match field.value, self._merge_parts, self._merge_authors:
109 case str(), _, _:
110 pass
111 case [*xs], True, False if all(isinstance(x, NameParts|NameParts_d) for x in xs):
112 # Merge nameparts, but not authors
113 merged = [merger(x) for x in xs]
114 result.append(model.Field(field.key, merged, start_line=field.start_line))
115 case [*xs], True, True if all(isinstance(x, NameParts|NameParts_d) for x in xs):
116 # Merge nameparts, then authors
117 merged = [merger(x) for x in xs]
118 joined = API_N.JOIN_STR.join(merged)
119 result.append(model.Field(field.key, joined, start_line=field.start_line))
120 case [*xs], _, True if all(isinstance(x, str) for x in xs) and self._merge_authors:
121 # Just merge authors
122 joined = API_N.JOIN_STR.join(xs)
123 result.append(model.Field(field.key, joined, start_line=field.start_line))
124 case _, False, False:
125 pass
126 case x, _, _:
127 return TypeError("Unexpected name type", entry.key, type(x))
128
129 return result
130
[docs]
131 def _merge_von_last_jr_first(self, name:NameParts|NameParts_d) -> str:
132 match name:
133 case NameParts() | NameParts_d():
134 pass
135 case x:
136 raise TypeError(type(x))
137
138 result = []
139 if name.von:
140 result.append(" ".join(name.von))
141 result.append(" ")
142
143 if name.last:
144 result.append(" ".join(name.last))
145 result.append(", ")
146
147 if name.jr:
148 result.append(" ".join(name.jr))
149 result.append(", ")
150
151 result.append(" ".join(name.first))
152
153 full_name = "".join(result).removesuffix(", ").strip()
154 return full_name