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
26from jgdv import Proto, Mixin
27import bibtexparser
28import bibtexparser.model as model
29from bibtexparser.library import Library
30from bibtexparser import exceptions as bexp
31from bibtexparser import middlewares as ms
32from bibtexparser.model import MiddlewareErrorBlock
33# ##-- end 3rd party imports
34
35# ##-- 1st party imports
36import bibble._interface as API
37from . import _interface as LAPI
38from bibble.util.mixins import ErrorRaiser_m, FieldMatcher_m
39from bibble.util.str_transform_m import StringTransform_m
40from ._util import UnicodeHelper_m
41from bibble.util.middlecore import IdenBlockMiddleware
42
43# ##-- end 1st party imports
44
45# ##-- types
46# isort: off
47import abc
48import collections.abc
49from typing import TYPE_CHECKING, cast, assert_type, assert_never
50from typing import Generic, NewType
51# Protocols:
52from typing import Protocol, runtime_checkable
53# Typing Decorators:
54from typing import no_type_check, final, override, overload
55
56if TYPE_CHECKING:
57 from jgdv import Maybe, VList, Result
58 from typing import Final
59 from typing import ClassVar, Any, LiteralString
60 from typing import Never, Self, Literal
61 from typing import TypeGuard
62 from collections.abc import Iterable, Iterator, Callable, Generator
63 from collections.abc import Sequence, Mapping, MutableMapping, Hashable
64
65 type Entry = model.Entry
66 type Block = model.Block
67 type Field = model.Field
68##--|
69
70# isort: on
71# ##-- end types
72
73##-- logging
74logging = logmod.getLogger(__name__)
75##-- end logging
76
77##--|
78
[docs]
79@Proto(API.ReadTime_p)
80@Mixin(UnicodeHelper_m, ErrorRaiser_m, FieldMatcher_m, StringTransform_m)
81class LatexReader(IdenBlockMiddleware):
82 """ Latex->unicode transform.
83 all strings in the library, except urls, files, doi's and crossrefs
84 """
85
86 _blacklist = ("url", "file", "doi", "crossref")
87 _total_rules : dict
88 _total_options : dict
89
90 def __init__(self, *, extra:Maybe[dict]=None, **kwargs):
91 super().__init__(**kwargs)
92 self.set_field_matchers(black=self._blacklist, white=[])
93 self._total_options = {
94 LAPI.KEEP_BRACED_K : kwargs.pop(LAPI.KEEP_BRACED_K, False),
95 LAPI.MATH_MODE_K : kwargs.pop(LAPI.MATH_MODE_K, 'text'),
96 }
97 self._total_rules : dict[str, VList[LAPI.MacroTextSpec]] = {
98 f"{self.metadata_key()}-simplify-urls" : self.build_decode_rule(LAPI.URL_SIMPL)
99 }
100 match extra:
101 case dict():
102 self._total_rules.update(extra)
103 case None:
104 pass
105
106 self.rebuild_decoder()
107
[docs]
108 def on_read(self):
109 Never()
110
[docs]
111 def transform_Entry(self, entry:Entry, library:Library) -> list[Block]:
112 match self.match_on_fields(entry, library):
113 case model.Entry() as x:
114 return [x]
115 case ValueError() as err:
116 return [self.make_error_block(entry, err)]
117
[docs]
118 def field_h(self, field:Field, entry:Entry) -> Result[list[Field], Exception]:
119 if field.value.startswith("{") and field.value.endswith("}"):
120 return [field]
121
122 match self.transform_strlike(field.value):
123 case Exception() as err:
124 return err
125 case x:
126 return [model.Field(key=field.key, value=x)]
127