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 import exceptions as bexp
29from bibtexparser import middlewares as ms
30from bibtexparser.model import MiddlewareErrorBlock
31from pylatexenc.latexencode import (RULE_REGEX, UnicodeToLatexConversionRule,
32 UnicodeToLatexEncoder)
33
34from jgdv import Proto, Mixin
35# ##-- end 3rd party imports
36
37# ##-- 1st party imports
38import bibble._interface as API
39from . import _interface as LAPI
40from ._util import UnicodeHelper_m
41from bibble.util.mixins import ErrorRaiser_m, FieldMatcher_m
42from bibble.util.str_transform_m import StringTransform_m
43from bibble.util.middlecore import IdenBlockMiddleware
44
45# ##-- end 1st party imports
46
47# ##-- types
48# isort: off
49import abc
50import collections.abc
51from typing import TYPE_CHECKING, cast, assert_type, assert_never
52from typing import Generic, NewType
53# Protocols:
54from typing import Protocol, runtime_checkable
55# Typing Decorators:
56from typing import no_type_check, final, override, overload
57
58if TYPE_CHECKING:
59 from jgdv import Maybe, Result
60 from typing import Final
61 from typing import ClassVar, Any, LiteralString
62 from typing import Never, Self, Literal
63 from typing import TypeGuard
64 from collections.abc import Iterable, Iterator, Callable, Generator
65 from collections.abc import Sequence, Mapping, MutableMapping, Hashable
66
67 type U2LRule = UnicodeToLatexConversionRule
68 type Entry = model.Entry
69 type Field = model.Field
70 type Block = model.Block
71 from bibtexparser.library import Library
72##--|
73
74# isort: on
75# ##-- end types
76
77##-- logging
78logging = logmod.getLogger(__name__)
79##-- end logging
80
81##--|
82
83##--|
84
[docs]
85@Proto(API.WriteTime_p, API.StrTransformer_p)
86@Mixin(UnicodeHelper_m, FieldMatcher_m, StringTransform_m)
87class LatexWriter(IdenBlockMiddleware):
88 """ Unicode->Latex Transform.
89 all strings in the library except urls, files, dois and crossrefs
90 see https://pylatexenc.readthedocs.io/en/latest/latexencode/
91
92 to customize the conversion rules, use pylatexenc.latexencode
93 and call rebuild_encoder with them
94
95 """
96
97 _blacklist = ("url", "file", "doi", "crossref")
98
99 def __init__(self, **kwargs):
100 kwargs.setdefault(API.ALLOW_INPLACE_MOD_K, False)
101 super().__init__(**kwargs)
102 self.set_field_matchers(black=self._blacklist, white=[])
103 self._total_options = {}
104 self._total_rules : list[U2LRule] = [
105 self.build_encode_rule(LAPI.ENCODING_RULES)
106 ]
107 if kwargs.get(API.KEEP_MATH_K, True):
108 self._total_rules.append(self.build_encode_rule(LAPI.MATH_RULES))
109
110 if kwargs.get(API.ENCLOSE_URLS_K, False):
111 self._total_rules.append(self.build_encode_rule(LAPI.URL_RULES))
112
113 self.rebuild_encoder()
114
[docs]
115 def on_write(self):
116 Never()
117
[docs]
118 def transform_Entry(self, entry:Entry, library:Library) -> list[Block]:
119 match self.match_on_fields(entry, library):
120 case model.Entry() as x:
121 return [x]
122 case Exception() as err:
123 return [self.make_error_block(entry, err)]
124 case x:
125 raise TypeError(type(x))
126
[docs]
127 def field_h(self, field:model.Field, entry:Entry) -> Result[list[Field], Exception]:
128 if field.value.startswith("{") and field.value.endswith("}"):
129 return [field]
130 match self.transform_strlike(field.value):
131 case Exception() as err:
132 return err
133 case x:
134 return [model.Field(key=field.key, value=x)]
135