Mostly functional in the new format

This commit is contained in:
Christopher T. Johnson
2024-04-12 11:18:39 -04:00
parent ad5904f3ae
commit a3d3e71bf8
3 changed files with 331 additions and 453 deletions

View File

@@ -37,7 +37,7 @@ class Fragment:
self._color = QColor() self._color = QColor()
self._background = QColor() self._background = QColor()
self._asis = asis self._asis = asis
self._left = 0 self._indent = 0
self._target = "word" self._target = "word"
return return
@@ -243,8 +243,8 @@ class Fragment:
def setBackground(self, color: QColor) -> None: def setBackground(self, color: QColor) -> None:
self._background = color self._background = color
return return
def setLeft(self, left: int) -> None: def setIndent(self, indent: int) -> None:
self._left = left self._indent = indent
return return
# #
@@ -292,8 +292,8 @@ class Fragment:
def asis(self) -> bool: def asis(self) -> bool:
return self._asis return self._asis
def left(self) -> int: def indent(self) -> int:
return self._left return self._indent
class Line: class Line:
def __init__(self) -> None: def __init__(self) -> None:
@@ -322,7 +322,7 @@ class Line:
def parseText(self, frag: Fragment) -> list[Fragment]: def parseText(self, frag: Fragment) -> list[Fragment]:
org = frag.text() org = frag.text()
if frag.asis(): if frag.asis() or True:
return [frag] return [frag]
# #
# Needed Fonts # Needed Fonts
@@ -537,8 +537,11 @@ class Line:
self._leading = leading self._leading = leading
x = 0 x = 0
for frag in self._fragments: for frag in self._fragments:
if x < frag.left(): left = frag.indent() * 30
x = frag.left() if left > 0:
print(frag.indent(), frag.text())
if x < left:
x = left
# #
# We need to calculate the location to draw the # We need to calculate the location to draw the
# text. We also need to calculate the bounding Rectangle # text. We also need to calculate the bounding Rectangle

View File

@@ -1,23 +1,18 @@
import importlib import importlib
import pkgutil import pkgutil
import json import json
import re
from typing import Any, TypedDict, cast from typing import Any, TypedDict, cast
from PyQt6.QtCore import ( from PyQt6.QtCore import (
QUrl,
Qt, Qt,
pyqtSlot, pyqtSlot,
) )
from PyQt6.QtGui import (
QColor,
)
from PyQt6.QtSql import QSqlQuery from PyQt6.QtSql import QSqlQuery
from PyQt6.QtWidgets import QScrollArea from PyQt6.QtWidgets import QScrollArea
from lib.utils import query_error, Resources from lib.utils import query_error
from lib.sounds import SoundOff from lib.sounds import SoundOff
from lib.definition import Definition, Line, Fragment from lib.definition import Definition, Line
import plugins import plugins
def find_plugins(ns_pkg): def find_plugins(ns_pkg):
@@ -108,281 +103,6 @@ class Word:
except KeyError: except KeyError:
raise Exception(f"Unknown source: {self.current['source']}") raise Exception(f"Unknown source: {self.current['source']}")
def mw_seq(self, seq: list[Any]) -> list[Line]:
r=Resources()
lines: list[Line] = []
outer = " "
inner = " "
for value in seq:
if value[0] == 'pseq':
continue
print(value[0])
print(value[1])
sense = value[1]
#
# The optional 'sn' field tells us what sort of labeling to do
#
sn = sense.get("sn", "")
sns = sn.split(" ")
if len(sns) == 2:
outer = sns[0]
inner = sns[1]
elif len(sns) == 1:
if inner == " ":
outer = sns[0]
else:
inner = sns[0]
try:
text = ", ".join(sense["sls"])
line = Line()
frag = Fragment(
f"{outer} {inner} ",
r.boldFont,
color=r.baseColor
)
outer = " "
line.addFragment(frag)
frag = Fragment(
text,
r.italicFont,
color=r.baseColor
)
frag.setLeft(30)
line.addFragment(frag)
except KeyError:
pass
try:
for dt in sense["dt"]:
if dt[0] == "text":
line = Line()
frag = Fragment(
f"{outer} {inner} ",
r.boldFont,
color=r.baseColor
)
outer = " "
frag.setLeft(10)
line.addFragment(frag)
frag = Fragment(
dt[1],
r.textFont,
color=r.baseColor
)
frag.setLeft(30)
line.addFragment(frag)
lines.append(line)
elif dt[0] == "vis":
for vis in dt[1]:
line = Line()
frag = Fragment(
f" ",
r.boldFont
)
frag.setLeft(45)
line.addFragment(frag)
line.addFragment(
Fragment(
vis["t"],
r.textFont,
color=QColor("#aaa"),
)
)
lines.append(line)
elif dt[0] == "uns":
for uns in dt[1]:
for seg in uns:
if seg[0] == "text":
try:
line = lines.pop()
except IndexError:
line = Line()
frag = Fragment(
"\u27F6 " + seg[1],
r.textFont,
color=r.baseColor
)
frag.setLeft(30)
line.addFragment(frag)
lines.append(line)
elif dt[0] == 'ca':
continue
else:
raise Exception(f"Unknown key {dt[0]} in {sense['dt']}")
except KeyError:
pass
return lines
def mw_def_entry(self, entry: dict[str, Any]) -> list[Line]:
r = Resources()
#
# Easy reference to colors
#
lines: list[Line] = []
line = Line()
hw = re.sub(r"\*", "", entry["hwi"]["hw"])
frag = Fragment(hw, r.headerFont, color=r.baseColor)
line.addFragment(frag)
frag = Fragment(
" " + entry["fl"], r.labelFont, color=r.linkColor
)
line.addFragment(frag)
lines.append(line)
if "vrs" in entry.keys():
line = Line()
space = ""
for vrs in entry["vrs"]:
frag = Fragment(
space + vrs["va"],
r.labelFont,
color=r.baseColor
)
space = " "
line.addFragment(frag)
lines.append(line)
if "prs" in entry["hwi"]:
line = Line()
frag = Fragment(
entry["hwi"]["hw"] + " ",
r.phonicFont,
color=r.baseColor,
)
line.addFragment(frag)
for prs in entry["hwi"]["prs"]:
audio = None
if audio is None:
audio = ""
frag = Fragment(
prs["mw"], r.phonicFont, color=r.linkColor
)
frag.setAudio(audio)
line.addFragment(frag)
lines.append(line)
if "ins" in entry.keys():
line = Line()
space = ""
for ins in entry["ins"]:
try:
frag = Fragment(
ins["il"], r.textFont, color=r.baseColor
)
line.addFragment(frag)
space = " "
except KeyError:
pass
frag = Fragment(
space + ins["if"],
r.boldFont,
color=r.baseColor
)
line.addFragment(frag)
space = "; "
lines.append(line)
if "lbs" in entry.keys():
line = Line()
frag = Fragment(
"; ".join(entry["lbs"]),
r.boldFont,
color=r.baseColor
)
line.addFragment(frag)
lines.append(line)
for value in entry["def"]: # has multiple 'sseg' or 'vd' init
for k, v in value.items():
if k == "sseq": # has multiple 'senses'
for seq in v:
rr = self.mw_seq(seq)
lines += rr
elif k == "vd":
line = Line()
line.addFragment(
Fragment(
v, r.italicFont, color=r.linkColor
)
)
lines.append(line)
return lines
def mw_html(self) -> str:
#
# Create the header, base word and its label
#
word = self.current['definition']["hwi"]["hw"]
label = self.current["fl"]
html = f'<h1 class="def-word">{word} <span class="def-label">{label}</span></h1>\n'
#
# If there are variants, then add them in an unordered list.
# CSS will make it pretty
#
if "vrs" in self.current.keys():
html += "<ul class=\"def-vrs'>\n"
html += "<li>"
html += "</li>\n<li>".join(
[vrs["va"] for vrs in self.current["vrs"]]
)
html += "</li>\n</ul>\n"
#
# If there is a pronunciation section, create it
#
if "prs" in self.current["hwi"].keys():
tmp = []
for prs in self.current["hwi"]["prs"]:
url = QUrl()
how = prs["mw"]
if url:
tmp.append(f'<a href="{url}">\\{how}\\</a>')
else:
tmp.append(f"\\{how}\\")
html += '<span class="def-phonetic">'
html += '</span><span="def-phonetic">'.join(tmp)
html += "</span>\n"
#
# If there are inflections, create a header for that.
#
if "ins" in self.current.keys():
html += '<h2 class="def-word">'
html += ", ".join([ins["if"] for ins in self.current["ins"]])
html += "</h2>\n"
#
# Start creating the definition section
#
html += "<ul class='def-outer'>\n"
for meaning in self.current["def"]:
html += f"<li>{meaning['vd']}\n"
html += '<ul class="def-inner">\n'
label = ""
for sseq in meaning["sseq"]:
for sense in sseq:
label = sense[1]["sn"]
sls = ""
if "sls" in sense[1].keys():
sls = ", ".join(sense[1]["sls"])
sls = f'<span class="def-sls">{sls}</span> '
for dt in sense[1]["dt"]:
if dt[0] == "text":
html += f'<li class="def-text"><span class="def-sn">{label}</span>{sls}{dt[1]}</li>\n'
elif dt[0] == "vis":
for vis in dt[1]:
html += (
f"<li class=\"def-vis\">{vis['t']}</li>\n"
)
else:
print(f"Do something with {dt[0]}")
html += "</ul>\n"
html += "</ul>\n"
return html
def apidictionary_html(self) -> str:
html = ""
return html
class DefinitionArea(QScrollArea): class DefinitionArea(QScrollArea):
def __init__(self, w: Word, *args: Any, **kwargs: Any) -> None: def __init__(self, w: Word, *args: Any, **kwargs: Any) -> None:
super(DefinitionArea, self).__init__(*args, *kwargs) super(DefinitionArea, self).__init__(*args, *kwargs)

View File

@@ -1,8 +1,9 @@
from importlib.abc import InspectLoader
from PyQt6.QtGui import QColor from PyQt6.QtGui import QColor
from trycast import trycast from trycast import trycast
import json import json
import re import re
from typing import Any, NamedTuple, NotRequired, TypedDict from typing import Any, Literal, NotRequired, TypedDict, cast
from PyQt6.QtCore import QEventLoop, QUrl, Qt from PyQt6.QtCore import QEventLoop, QUrl, Qt
from PyQt6.QtNetwork import QNetworkRequest from PyQt6.QtNetwork import QNetworkRequest
@@ -17,15 +18,14 @@ registration = {
API = "https://www.dictionaryapi.com/api/v3/references/collegiate/json/{word}?key={key}" API = "https://www.dictionaryapi.com/api/v3/references/collegiate/json/{word}?key={key}"
key = "51d9df34-ee13-489e-8656-478c215e846c" key = "51d9df34-ee13-489e-8656-478c215e846c"
class TextTuple(NamedTuple): class Meta(TypedDict):
type_: str # 'text' id: str
text: str uuid: str
class TTuple(NamedTuple): sort: str
type_: str # 't' src: str
text: str section: str
class VerbalIllustration(TypedDict): stems: list[str]
t: str offensive: bool
aq: str
class Sound(TypedDict): class Sound(TypedDict):
audio: str audio: str
@@ -39,73 +39,70 @@ class Pronunciation(TypedDict):
pun: NotRequired[str] pun: NotRequired[str]
sound: NotRequired[Sound] sound: NotRequired[Sound]
class Meta(TypedDict): class SubSource(TypedDict):
id: str source: NotRequired[str]
uuid: str aqdate: NotRequired[str]
sort: str
src: str
section: str
stems: list[str]
offensive: bool
class HeadWordInfo(TypedDict): class AttributionOfQuote(TypedDict):
auth: NotRequired[str]
source: NotRequired[str]
aqdate: NotRequired[str]
subsource: NotRequired[SubSource]
class VerbalIllustration(TypedDict):
t: str
aq: NotRequired[AttributionOfQuote]
class HeadWordInformation(TypedDict):
hw: str hw: str
prs: NotRequired[list[Pronunciation]] prs: NotRequired[list[Pronunciation]]
class HeadWord(TypedDict): class AlternanteHeadword(TypedDict):
hw: str hw: str
prs: NotRequired[list[Pronunciation]]
psl: NotRequired[str] psl: NotRequired[str]
class Variant(TypedDict): class Variant(TypedDict):
va: str va: str
vl: str vl: NotRequired[str]
prs: list[Pronunciation] prs: NotRequired[list[Pronunciation]]
spl: str spl: NotRequired[str]
class Inflection(TypedDict): Inflection =TypedDict('Inflection', {
if_: str 'if': NotRequired[str],
ifc: str 'ifc': NotRequired[str],
il: str 'il': NotRequired[str],
prs: list[Pronunciation] 'prs': NotRequired[list[Pronunciation]],
spl: str 'spl': NotRequired[str]
})
class CrossReferenceTarget(TypedDict):
cxl: str
cxr: NotRequired[str]
cxt: str
cxn: NotRequired[str]
class CognateCrossRef(TypedDict):
cxl: str
cxtis: list[CrossReferenceTarget]
class Pair(TypedDict):
objType: str
obj: Any
class DividedSense(TypedDict): class DividedSense(TypedDict):
sd: str sd: str
et: list[str] # Not full dt: list[list[Pair]]
ins: list[Inflection] et: NotRequired[list[Pair]]
lbs: list[str] ins: NotRequired[list[Inflection]]
prs: list[Pronunciation] lbs: NotRequired[list[str]]
sgram: str prs: NotRequired[list[Pronunciation]]
sls: list[str] sgram: NotRequired[str]
vrs: list[Variant] sls: NotRequired[list[str]]
vrs: NotRequired[list[Variant]]
class BioGraphicalNameWrap(TypedDict):
pname: str
sname: str
altname: str
prs: list[Pronunciation]
class CalledAlsoTarget(TypedDict):
cat: str
catref: str
pn: str
prs: list[Pronunciation]
psl: str
class CalledAlso(TypedDict):
intro: str
cats: list[CalledAlsoTarget]
class RunInWrap(TypedDict):
rie: str
prs: list[Pronunciation]
text: str
vrs: list[Variant]
class Sense(TypedDict): class Sense(TypedDict):
dt: list[list] # not full dt: list[list[Pair]]
et: NotRequired[list[str]] et: NotRequired[list[Pair]]
ins: NotRequired[list[Inflection]] ins: NotRequired[list[Inflection]]
lbs: NotRequired[list[str]] lbs: NotRequired[list[str]]
prs: NotRequired[list[Pronunciation]] prs: NotRequired[list[Pronunciation]]
@@ -115,43 +112,93 @@ class Sense(TypedDict):
sn: NotRequired[str] sn: NotRequired[str]
vrs: NotRequired[list[Variant]] vrs: NotRequired[list[Variant]]
class Definition(TypedDict): class TruncatedSense(Sense): pass
sseq: list[list[list[Any]]]
class BindingSubstitutePair(TypedDict):
objType: Literal['bs']
obj: Sense
class SensePair(TypedDict):
objType: Literal['sense']
obj: Sense
class DefinitionSection(TypedDict):
vd: NotRequired[str] vd: NotRequired[str]
sls: NotRequired[list[str]]
sseq: Any # list[list[Pair]]
class Pair(TypedDict): Definition =TypedDict('Definition', {
objType: str 'meta': Meta,
obj: list[Sense]|Sense|str|list[VerbalIllustration]|list[Any] 'hom': NotRequired[int],
'hwi': HeadWordInformation,
Entry = TypedDict( 'ahws': NotRequired[list[AlternanteHeadword]],
'Entry', 'vrs': NotRequired[list[Variant]],
{ 'fl': str,
'meta': Meta, 'lbs': NotRequired[list[str]],
'hom': NotRequired[str], 'sls': NotRequired[list[str]],
'hwi': HeadWordInfo, 'ins': NotRequired[list[Inflection]],
'ahws': NotRequired[list[HeadWord]], 'cxs': NotRequired[list[CognateCrossRef]],
'vrs': NotRequired[list[Variant]], 'def': list[DefinitionSection],
'fl': NotRequired[str], })
'def': list[Definition],
}
)
class WordType(TypedDict):
word: str
source: str
definition: dict[str, Any]
def make_pairs(src: list[Any]) -> list[Pair]: def make_pairs(src: list[Any]) -> list[Pair]:
result:list[Pair] = [] result:list[Pair] = []
iters = [iter(src)]*2 iters = [iter(src)]*2
for entry in zip(*iters): for entry in zip(*iters):
pair = { 'objType': entry[0], pair0 = { 'objType': entry[0],
'obj': entry[1], 'obj': entry[1],
} }
pair = trycast(Pair, pair) if isinstance(pair0['obj'], list):
assert pair is not None result.append(cast(Pair,pair0))
result.append(pair) continue
pair1 = trycast(Pair, pair0)
if pair1 is None:
print(pair0['objType'], type(pair0['obj']),
json.dumps(pair0['obj'],indent=2)
)
assert pair1 is not None
result.append(pair1)
return result return result
Elements = [ 'dt', 'sen', 'bs', 'pseq', 'snot', 't', 'text', 'vis', 'sens', 'uns', 'sense' ]
def restructure(obj: Any) -> Any:
if isinstance(obj, list):
if len(obj) == 0:
return []
if isinstance(obj[0], str) and obj[0] in Elements:
pairs = make_pairs(obj)
result = []
for pair in pairs:
if isinstance(pair['obj'], list):
r2 = []
for item in pair['obj']:
r2.append(restructure(item))
pair['obj'] = r2
elif isinstance(pair['obj'], dict):
r2 = {}
for k,v in pair['obj'].items():
r2[k] = restructure(v)
pair['obj'] = r2
result.append(pair)
return result
result = []
for v in obj:
result.append(restructure(v))
return result
elif isinstance(obj, dict):
obj2 = cast(dict, obj)
result = {}
for k,v in obj2.items():
result[k] = restructure(v)
return result
else:
return obj
class WordType(TypedDict):
word: str
source: str
definition: Any
def fetch(word:str) -> WordType: def fetch(word:str) -> WordType:
request = QNetworkRequest() request = QNetworkRequest()
url = QUrl(API.format(word=word, key=key)) url = QUrl(API.format(word=word, key=key))
@@ -182,11 +229,11 @@ def soundUrl(sound:Sound, fmt='ogg') -> QUrl:
url += audio + f".{fmt}" url += audio + f".{fmt}"
return QUrl(url) return QUrl(url)
def getFirstSound(definition: list[Entry]) -> QUrl: def getFirstSound(definition: Any) -> QUrl:
# ahws, cats, dros, hwi, ins, ri, sdsense, sen, sense, uros, vrs # ahws, cats, dros, hwi, ins, ri, sdsense, sen, sense, uros, vrs
for entry in definition: for entry in definition:
for v in entry.values(): for v in entry.values():
hwi = trycast(HeadWordInfo, v) hwi = v # trycast
if hwi is None: if hwi is None:
continue continue
if 'prs' in hwi: if 'prs' in hwi:
@@ -197,7 +244,7 @@ def getFirstSound(definition: list[Entry]) -> QUrl:
return url return url
return QUrl() return QUrl()
def do_prs(hwi: HeadWordInfo) -> list[Fragment]: def do_prs(hwi: Any) -> list[Fragment]:
r = Resources() r = Resources()
frags: list[Fragment] = [] frags: list[Fragment] = []
font = r.labelFont font = r.labelFont
@@ -226,49 +273,153 @@ def do_prs(hwi: HeadWordInfo) -> list[Fragment]:
) )
return frags return frags
def do_sense(sense: Sense|None) -> tuple[list[Fragment], list[Line]]: def do_aq(aq: AttributionOfQuote|None) -> list[Line]:
assert aq is not None
return []
def do_vis(vis: list[VerbalIllustration]|None,indent=0) -> list[Line]:
assert vis is not None
r = Resources()
lines: list[Line] = []
for vi in vis:
line = Line()
frag = Fragment(vi['t'], r.textFont, color=r.baseColor)
if indent > 0:
frag.setIndent(indent)
line.addFragment(frag)
lines.append(line)
if 'aq' in vi:
lines += do_aq(trycast(AttributionOfQuote, vi['aq']))
return []
def do_uns(uns: list[list[list[Pair]]]|None, indent:int) -> list[Line]:
assert uns is not None
r = Resources()
lines:list[Line] = []
for note in uns:
for entry in note:
for pair in entry:
if pair['objType'] == 'text':
frag = Fragment(' \u2014'+pair['obj'], r.textFont, color=r.baseColor)
frag.setIndent(indent)
line = Line()
line.addFragment(frag)
lines.append(line)
elif pair['objType'] == 'vis':
lines += do_vis(trycast(list[VerbalIllustration], pair['obj']), indent)
elif pair['objType'] == 'ri':
raise NotImplementedError("NO ri")
return lines
def do_dt(dt: list[list[Pair]]|None, indent: int) -> tuple[list[Fragment], list[Line]]:
assert dt is not None
frags: list[Fragment] = []
lines: list[Line] = []
r = Resources()
first = True
for entry in dt:
for pair in entry:
if pair['objType'] == 'text':
frag = Fragment(pair['obj'], r.textFont, color=r.baseColor)
frag.setIndent(indent)
if first:
frags.append(frag)
else:
line = Line()
line.addFragment(frag)
lines.append(line)
elif pair['objType'] == 'vis':
lines += do_vis(trycast(list[VerbalIllustration], pair['obj']))
elif pair['objType'] == 'uns':
newLines = do_uns(trycast(list[list[list[Pair]]], pair['obj']),indent)
lines += newLines
else:
print(json.dumps(pair, indent=2))
raise NotImplementedError(f"Unknown or unimplimented element {pair['objType']}")
first = False
return (frags, lines)
def do_sense(sense: Sense|None, indent:int=3) -> tuple[list[Fragment], list[Line]]:
if sense is None: if sense is None:
return ([],[]) return ([],[])
lines: list[Line] = [] lines: list[Line] = []
frags: list[Fragment] = [] frags: list[Fragment] = []
r = Resources() r = Resources()
if 'sn' in sense: dt = sense['dt']
sn = sense['sn'] (newFrags, newLines) = do_dt(trycast(list[list[Pair]], dt),indent)
else: frags += newFrags
sn = '' lines += newLines
print(f'{sn}\n\n',json.dumps(sense['dt'], indent=2)) for k,v in sense.items():
iters = [iter(sense['dt'])]*2 print(k)
for pair in zip(*iters): if k == 'dt' or k == 'sn':
pair = trycast(tuple[str, Any], pair) continue
assert pair is not None elif k == 'sdsense':
print(pair[0]) # XXX - This needs to expand to handle et, ins, lbs, prs, sgram, sls, vrs
if pair[0] == 'text': sdsense = trycast(DividedSense, v)
assert sdsense is not None
frag = Fragment(sdsense['sd']+' ', r.italicFont, color=r.baseColor)
frag.setIndent(indent)
line = Line() line = Line()
line.addFragment( line.addFragment(frag)
Fragment(pair[1], r.textFont, color=r.baseColor) (newFrags, newLines) = do_dt(trycast(list[list[Pair]], sdsense['dt']), indent=indent)
) for frag in newFrags:
line.addFragment(frag)
lines.append(line) lines.append(line)
lines += newLines
elif k == 'sls':
labels = trycast(list[str], v)
assert labels is not None
frag = Fragment(", ".join(labels)+' ', r.textFont, color=r.subduedColor)
frags.append(frag)
else:
print(k,v)
raise NotImplementedError(f"Unknown or unimplimented element {k}")
return (frags, lines) return (frags, lines)
def do_pseq(outer: int, def do_pseq(outer: int,
inner: int, inner: int,
pseq: list[list[Pair]]| None ) -> tuple[list[Fragment], list[Line]]: pseq: list[Any] ) -> tuple[list[Fragment], list[Line]]:
assert pseq is not None
lines: list[Line] = [] lines: list[Line] = []
frags: list[Fragment] = [] frags: list[Fragment] = []
count = 1
r = Resources()
first = True
for entry in pseq: for entry in pseq:
pairs = make_pairs(entry) for pair in entry:
for pair in pairs:
if pair['objType'] == 'bs': if pair['objType'] == 'bs':
(newFrags, newLines) = do_sense(trycast(Sense, pair['obj'])) # TODO - bs has to be more than just a wrapper for Sense
frags += newFrags sense = pair['obj']['sense']
(newFrags, newLines) = do_sense(trycast(Sense, sense))
if first:
frags += newFrags
first = False
else:
line = Line()
for frag in newFrags:
line.addFragment(frag)
lines.append(line)
lines += newLines lines += newLines
elif pair['objType'] == 'sense': elif pair['objType'] == 'sense':
(newFrags, newLines) = do_sense(trycast(Sense, pair['obj'])) if first:
frags += newFrags frag = Fragment(f"({count})", r.textFont, color=r.baseColor)
frag.setIndent(3)
frags.append(frag)
(newFrags, newLines) = do_sense(trycast(Sense, pair['obj']), indent=4)
frags += newFrags
first = False
else:
line = Line()
frag = Fragment(f"({count})", r.textFont, color=r.baseColor)
frag.setIndent(3)
line.addFragment(frag)
(newFrags, newLines) = do_sense(trycast(Sense, pair['obj']), indent=4)
for frag in newFrags:
line.addFragment(frag)
lines.append(line)
lines += newLines lines += newLines
count += 1
else: else:
raise Exception(f"Unknown object type {pair['objType']}") raise NotImplementedError(f"Unknown object type {pair['objType']}")
return (frags, lines) return (frags, lines)
def do_sseq(sseq:list[list[list[Pair]]]) -> list[Line]: def do_sseq(sseq:list[list[list[Pair]]]) -> list[Line]:
@@ -276,15 +427,14 @@ def do_sseq(sseq:list[list[list[Pair]]]) -> list[Line]:
r = Resources() r = Resources()
for outer, item_o in enumerate(sseq): for outer, item_o in enumerate(sseq):
line = Line() line = Line()
line.addFragment( frag =Fragment(str(outer+1), r.boldFont, color=r.baseColor)
Fragment(str(outer+1), r.boldFont, color=r.baseColor) frag.setIndent(1)
) line.addFragment(frag)
for inner, item_i in enumerate(item_o): for inner, item_i in enumerate(item_o):
line.addFragment( frag =Fragment(chr(ord('a')+inner), r.boldFont, color=r.baseColor)
Fragment(chr(ord('a')+inner), r.boldFont, color=r.baseColor) frag.setIndent(2)
) line.addFragment(frag)
pairs = make_pairs(item_i) for pair in item_i:
for pair in pairs:
objType = pair['objType'] objType = pair['objType']
if objType == 'sense': if objType == 'sense':
sense = trycast(Sense, pair['obj']) sense = trycast(Sense, pair['obj'])
@@ -292,26 +442,27 @@ def do_sseq(sseq:list[list[list[Pair]]]) -> list[Line]:
for frag in frags: for frag in frags:
line.addFragment(frag) line.addFragment(frag)
lines.append(line) lines.append(line)
line = Line()
lines += newlines lines += newlines
elif objType == 'sen': elif objType == 'sen':
raise Exception(f"sen unimplimented") raise NotImplementedError(f"sen unimplimented")
elif objType == 'pseq': elif objType == 'pseq':
pseq = trycast(list[list[Pair]], pair['obj']) (frags, newlines) = do_pseq(inner, outer, pair['obj'])
(frags, newlines) = do_pseq(inner, outer, trycast(list[list[Pair]], pair['obj']))
for frag in frags: for frag in frags:
line.addFragment(frag) line.addFragment(frag)
lines.append(line) lines.append(line)
line = Line()
lines += newlines lines += newlines
elif objType == 'bs': elif objType == 'bs':
raise Exception(f"bs unimplimented") raise NotImplementedError(f"bs unimplimented")
else: else:
raise Exception(f"Unknown object[{objType}] for \n{json.dumps(pair['obj'],indent=2)}") raise NotImplementedError(f"Unknown object[{objType}] for \n{json.dumps(pair['obj'],indent=2)}")
return lines return lines
def do_def(entry: Definition) -> list[Line]: def do_def(entry: DefinitionSection) -> list[Line]:
assert entry is not None
r = Resources() r = Resources()
lines: list[Line] = [] lines: list[Line] = []
assert trycast(Definition, entry) is not None
if 'vd' in entry: if 'vd' in entry:
line = Line() line = Line()
line.addFragment( line.addFragment(
@@ -325,67 +476,68 @@ def do_def(entry: Definition) -> list[Line]:
lines += do_sseq(sseq) lines += do_sseq(sseq)
return lines return lines
def getDef(definition: list[Entry]) -> list[Line]: def getDef(defines: Any) -> list[Line]:
workList = restructure(defines)
workList = trycast(list[Definition], workList)
assert workList is not None
r = Resources() r = Resources()
lines:list[Line] = [] lines:list[Line] = []
#
# Pull the fonts for ease of use
#
headerFont = r.headerFont
textFont = r.textFont
labelFont = r.labelFont
#
# Pull the colors for ease of use
#
baseColor = r.baseColor
linkColor = r.linkColor
subduedColor = r.subduedColor
# #
# No need to figure it out each time it is used # No need to figure it out each time it is used
# #
entries = 0 entries = 0
id = definition[0]['meta']['id'].lower().split(':')[0] id = workList[0]['meta']['id'].lower().split(':')[0]
uses: dict[str,int] = {} uses: dict[str,int] = {}
for entry in definition: for entry in workList:
testId = entry['meta']['id'].lower().split(':')[0] testId = entry['meta']['id'].lower().split(':')[0]
if testId == id: if testId == id:
entries += 1 entries += 1
#
# If there is a Functional Lable, then we are going
# to capture the count of each FL
#
try: try:
uses[entry['fl']] = uses.get(entry['fl'], 0) + 1 uses[entry['fl']] = uses.get(entry['fl'], 0) + 1
except KeyError: except KeyError:
pass pass
del(entry)
used: dict[str, int] = {} used: dict[str, int] = {}
for k in uses.keys(): for k in uses.keys():
used[k] = 0 used[k] = 0
for count, entry in enumerate(definition):
testId = entry['meta']['id'].lower().split(':')[0] for count, work in enumerate(workList):
testId = work['meta']['id'].lower().split(':')[0]
#
# Skip entries which are not part of the primary definition
#
if testId != id: if testId != id:
continue continue
# #
# Create the First line from the hwi, [ahws] and fl # Create the First line from the hwi, [ahws] and fl
# #
line = Line() line = Line()
hwi = trycast(HeadWordInfo, entry['hwi']) hwi = trycast(HeadWordInformation, work['hwi'])
assert hwi is not None assert hwi is not None
hw = re.sub(r'\*', '', hwi['hw']) hw = re.sub(r'\*', '', hwi['hw'])
line.addFragment(Fragment(hw, headerFont, color=baseColor)) line.addFragment(Fragment(hw, r.headerFont, color=r.baseColor))
if 'ahws' in entry: if 'ahws' in work:
ahws = trycast(list[HeadWord], entry['ahws']) ahws = trycast(list[AlternanteHeadword], work['ahws'])
assert ahws is not None assert ahws is not None
for ahw in ahws: for ahw in ahws:
hw = re.sub(r'\*', '', ahw['hw']) hw = re.sub(r'\*', '', ahw['hw'])
line.addFragment(Fragment(', ' + hw, headerFont, color=baseColor)) line.addFragment(Fragment(', ' + hw, r.headerFont, color=r.baseColor))
if entries > 1: if entries > 1:
frag = Fragment(f" {count + 1} of {entries} ", textFont, color= subduedColor) frag = Fragment(f" {count + 1} of {entries} ", r.textFont, color= r.subduedColor)
# XXX - Use a resource color!!!
frag.setBackground(QColor(Qt.GlobalColor.gray)) frag.setBackground(QColor(Qt.GlobalColor.gray))
line.addFragment(frag) line.addFragment(frag)
if 'fl' in entry: if 'fl' in work:
text = entry['fl'] text = work['fl']
used[text] += 1 used[text] += 1
if uses[text] > 1: if uses[text] > 1:
text += f' ({used[text]})' text += f' ({used[text]})'
line.addFragment(Fragment(text, labelFont, color=baseColor)) line.addFragment(Fragment(text, r.labelFont, color=r.baseColor))
lines.append(line) lines.append(line)
# #
@@ -395,13 +547,16 @@ def getDef(definition: list[Entry]) -> list[Line]:
line = Line() line = Line()
if hwi['hw'].find('*') >= 0: if hwi['hw'].find('*') >= 0:
hw = re.sub(r'\*', '\u00b7', hwi['hw']) hw = re.sub(r'\*', '\u00b7', hwi['hw'])
line.addFragment(Fragment(hw + ' ', textFont, color=subduedColor)) line.addFragment(Fragment(hw + ' ', r.textFont, color=r.subduedColor))
for frag in do_prs(hwi): for frag in do_prs(hwi):
line.addFragment(frag) line.addFragment(frag)
if len(line.getLine()) > 0: if len(line.getLine()) > 0:
lines.append(line) lines.append(line)
defines = trycast(list[Definition], entry['def']) defines = trycast(list[DefinitionSection], work['def'])
assert defines is not None assert defines is not None
for define in defines: for define in defines:
lines += do_def(define) try:
lines += do_def(define)
except NotImplementedError as e:
print(e)
return lines return lines