checkpoint

This commit is contained in:
Christopher T. Johnson
2024-04-09 11:45:56 -04:00
parent 46580b75ea
commit ad5904f3ae
3 changed files with 312 additions and 182 deletions

View File

@@ -1,7 +1,9 @@
"""Utility Functions.""" """Utility Functions."""
from typing import NoReturn from typing import NoReturn, Self
from PyQt6.QtCore import QCoreApplication from PyQt6.QtCore import QCoreApplication, QDir, QStandardPaths, Qt
from PyQt6.QtGui import QColor, QFont, QFontDatabase
from PyQt6.QtNetwork import QNetworkAccessManager, QNetworkDiskCache
from PyQt6.QtSql import QSqlQuery from PyQt6.QtSql import QSqlQuery
translate = QCoreApplication.translate translate = QCoreApplication.translate
@@ -19,3 +21,72 @@ def query_error(query: QSqlQuery) -> NoReturn:
) )
) )
raise Exception(translate("MainWindow", "SQL Error")) raise Exception(translate("MainWindow", "SQL Error"))
class Resources:
_instance = None
nam = QNetworkAccessManager()
headerFont: QFont
labelFont: QFont
boldFont: QFont
textFont: QFont
italicFont: QFont
capsFont: QFont
smallCapsFont: QFont
phonicFont: QFont
baseColor: QColor
linkColor: QColor
subduedColor: QColor
def __new__(cls: type[Self]) -> Self:
if cls._instance:
return cls._instance
cls._instance = super(Resources, cls).__new__(cls)
return cls._instance
def __init__(self) -> None:
super(Resources, self).__init__()
#
# Fonts
#
self.headerFont = QFontDatabase.font("OpenDyslexic", None, 10)
self.headerFont.setPixelSize(48)
self.labelFont = QFont(self.headerFont)
self.labelFont.setPixelSize(30)
self.boldFont = QFont(self.headerFont)
self.boldFont.setPixelSize(20)
self.textFont = QFont(self.boldFont)
self.italicFont = QFont(self.boldFont)
self.capsFont = QFont(self.boldFont)
self.smallCapsFont = QFont(self.boldFont)
self.headerFont.setWeight(QFont.Weight.Bold)
self.boldFont.setBold(True)
self.italicFont.setItalic(True)
self.capsFont.setCapitalization(QFont.Capitalization.AllUppercase)
self.smallCapsFont.setCapitalization(QFont.Capitalization.SmallCaps)
self.phonicFont = QFontDatabase.font("Gentium", None, 10)
self.phonicFont.setPixelSize(20)
#
# colors
#
self.baseColor = QColor(Qt.GlobalColor.white)
self.linkColor = QColor("#4a7d95")
self.subduedColor = QColor(Qt.GlobalColor.gray)
#
# Setup the Network Manager
#
cacheDir = QDir(
QStandardPaths.writableLocation(
QStandardPaths.StandardLocation.GenericCacheLocation
)
)
cacheDir.mkdir("Troglodite")
cacheDir = QDir(cacheDir.path() + QDir.separator() + "Troglodite")
netCache = QNetworkDiskCache()
netCache.setCacheDirectory(cacheDir.path())
self.nam.setCache(netCache)
return

View File

@@ -2,22 +2,20 @@ import importlib
import pkgutil import pkgutil
import json import json
import re import re
from typing import Any, Dict, cast from typing import Any, TypedDict, cast
from PyQt6.QtCore import ( from PyQt6.QtCore import (
QUrl,
Qt, Qt,
pyqtSlot, pyqtSlot,
) )
from PyQt6.QtGui import ( from PyQt6.QtGui import (
QColor, QColor,
QFont,
QFontDatabase,
) )
from PyQt6.QtNetwork import QNetworkAccessManager
from PyQt6.QtSql import QSqlQuery from PyQt6.QtSql import QSqlQuery
from PyQt6.QtWidgets import QScrollArea from PyQt6.QtWidgets import QScrollArea
from lib import query_error from lib.utils import query_error, Resources
from lib.sounds import SoundOff from lib.sounds import SoundOff
from lib.definition import Definition, Line, Fragment from lib.definition import Definition, Line, Fragment
@@ -32,20 +30,22 @@ discovered_plugins = {
API = "https://api.dictionaryapi.dev/api/v2/entries/en/{word}" API = "https://api.dictionaryapi.dev/api/v2/entries/en/{word}"
class WordType(TypedDict):
word: str
source: str
definition: str
class Word: class Word:
"""All processing of a dictionary word.""" """All processing of a dictionary word."""
_words: dict[str, Any] = {} _words: dict[str, WordType] = {}
_resources: Dict[str, Any] = {}
_nam = QNetworkAccessManager()
def __init__(self, word: str) -> None: def __init__(self, word: str) -> None:
Word.set_resources()
# #
# Have we already retrieved this word? # Have we already retrieved this word?
# #
try: try:
self.current = json.loads(Word._words[word]) self.current = Word._words[word]
return return
except KeyError: except KeyError:
pass pass
@@ -82,50 +82,6 @@ class Word:
query_error(query) query_error(query)
return return
@classmethod
def set_resources(cls) -> None:
if len(cls._resources.keys()) > 0:
return
#
# Colors we used
#
headerFont = QFontDatabase.font("OpenDyslexic", None, 10)
headerFont.setPixelSize(48)
labelFont = QFont(headerFont)
labelFont.setPixelSize(30)
boldFont = QFont(headerFont)
boldFont.setPixelSize(20)
textFont = QFont(boldFont)
italicFont = QFont(boldFont)
capsFont = QFont(boldFont)
smallCapsFont = QFont(boldFont)
headerFont.setWeight(QFont.Weight.Bold)
boldFont.setBold(True)
italicFont.setItalic(True)
capsFont.setCapitalization(QFont.Capitalization.AllUppercase)
smallCapsFont.setCapitalization(QFont.Capitalization.SmallCaps)
phonicFont = QFontDatabase.font("Gentium", None, 10)
phonicFont.setPixelSize(20)
cls._resources = {
"colors": {
"base": QColor(Qt.GlobalColor.white),
"link": QColor("#4a7d95"),
"subdued": QColor(Qt.GlobalColor.gray),
},
"fonts": {
"header": headerFont,
"label": labelFont,
"phonic": phonicFont,
"bold": boldFont,
"italic": italicFont,
"text": textFont,
"caps": capsFont,
"smallCaps": smallCapsFont,
},
}
@pyqtSlot() @pyqtSlot()
def playSound(self) -> None: def playSound(self) -> None:
url = discovered_plugins[self.current['source']].getFirstSound(self.current['definition']) url = discovered_plugins[self.current['source']].getFirstSound(self.current['definition'])
@@ -145,23 +101,15 @@ class Word:
raise Exception(f"Unknown source: {src}") raise Exception(f"Unknown source: {src}")
def get_def(self) -> list[Line]: def get_def(self) -> list[Line]:
if len(self._lines) > 0:
return self._lines
src = self.current['source'] src = self.current['source']
try: try:
return discovered_plugins[src].getDef(self.current) lines = discovered_plugins[src].getDef(self.current["definition"])
return lines
except KeyError: except KeyError:
raise Exception(f"Unknown source: {self.current['source']}") raise Exception(f"Unknown source: {self.current['source']}")
def mw_def(self) -> list[Line]:
lines: list[Line] = []
# print(json.dumps(self.current,indent=2))
for entry in self.current["definition"]:
lines += self.mw_def_entry(entry)
self._lines = lines
return lines
def mw_seq(self, seq: list[Any]) -> list[Line]: def mw_seq(self, seq: list[Any]) -> list[Line]:
r=Resources()
lines: list[Line] = [] lines: list[Line] = []
outer = " " outer = " "
inner = " " inner = " "
@@ -189,15 +137,15 @@ class Word:
line = Line() line = Line()
frag = Fragment( frag = Fragment(
f"{outer} {inner} ", f"{outer} {inner} ",
self._resources["fonts"]["bold"], r.boldFont,
color=self._resources["colors"]["base"], color=r.baseColor
) )
outer = " " outer = " "
line.addFragment(frag) line.addFragment(frag)
frag = Fragment( frag = Fragment(
text, text,
self._resources["fonts"]["italic"], r.italicFont,
color=self._resources["colors"]["base"], color=r.baseColor
) )
frag.setLeft(30) frag.setLeft(30)
line.addFragment(frag) line.addFragment(frag)
@@ -209,16 +157,16 @@ class Word:
line = Line() line = Line()
frag = Fragment( frag = Fragment(
f"{outer} {inner} ", f"{outer} {inner} ",
self._resources["fonts"]["bold"], r.boldFont,
color=self._resources["colors"]["base"], color=r.baseColor
) )
outer = " " outer = " "
frag.setLeft(10) frag.setLeft(10)
line.addFragment(frag) line.addFragment(frag)
frag = Fragment( frag = Fragment(
dt[1], dt[1],
self._resources["fonts"]["text"], r.textFont,
color=self._resources["colors"]["base"], color=r.baseColor
) )
frag.setLeft(30) frag.setLeft(30)
line.addFragment(frag) line.addFragment(frag)
@@ -228,14 +176,14 @@ class Word:
line = Line() line = Line()
frag = Fragment( frag = Fragment(
f" ", f" ",
self._resources["fonts"]["bold"], r.boldFont
) )
frag.setLeft(45) frag.setLeft(45)
line.addFragment(frag) line.addFragment(frag)
line.addFragment( line.addFragment(
Fragment( Fragment(
vis["t"], vis["t"],
self._resources["fonts"]["text"], r.textFont,
color=QColor("#aaa"), color=QColor("#aaa"),
) )
) )
@@ -250,8 +198,8 @@ class Word:
line = Line() line = Line()
frag = Fragment( frag = Fragment(
"\u27F6 " + seg[1], "\u27F6 " + seg[1],
self._resources["fonts"]["text"], r.textFont,
color=self._resources["colors"]["base"], color=r.baseColor
) )
frag.setLeft(30) frag.setLeft(30)
line.addFragment(frag) line.addFragment(frag)
@@ -265,19 +213,17 @@ class Word:
return lines return lines
def mw_def_entry(self, entry: dict[str, Any]) -> list[Line]: def mw_def_entry(self, entry: dict[str, Any]) -> list[Line]:
r = Resources()
# #
# Easy reference to colors # Easy reference to colors
# #
base = self._resources["colors"]["base"]
blue = self._resources["colors"]["blue"]
lines: list[Line] = [] lines: list[Line] = []
line = Line() line = Line()
hw = re.sub(r"\*", "", entry["hwi"]["hw"]) hw = re.sub(r"\*", "", entry["hwi"]["hw"])
frag = Fragment(hw, self._resources["fonts"]["header"], color=base) frag = Fragment(hw, r.headerFont, color=r.baseColor)
line.addFragment(frag) line.addFragment(frag)
frag = Fragment( frag = Fragment(
" " + entry["fl"], self._resources["fonts"]["label"], color=blue " " + entry["fl"], r.labelFont, color=r.linkColor
) )
line.addFragment(frag) line.addFragment(frag)
lines.append(line) lines.append(line)
@@ -288,8 +234,8 @@ class Word:
for vrs in entry["vrs"]: for vrs in entry["vrs"]:
frag = Fragment( frag = Fragment(
space + vrs["va"], space + vrs["va"],
self._resources["fonts"]["label"], r.labelFont,
color=base, color=r.baseColor
) )
space = " " space = " "
line.addFragment(frag) line.addFragment(frag)
@@ -298,16 +244,16 @@ class Word:
line = Line() line = Line()
frag = Fragment( frag = Fragment(
entry["hwi"]["hw"] + " ", entry["hwi"]["hw"] + " ",
self._resources["fonts"]["phonic"], r.phonicFont,
color=base, color=r.baseColor,
) )
line.addFragment(frag) line.addFragment(frag)
for prs in entry["hwi"]["prs"]: for prs in entry["hwi"]["prs"]:
audio = self.mw_sound_url(prs) audio = None
if audio is None: if audio is None:
audio = "" audio = ""
frag = Fragment( frag = Fragment(
prs["mw"], self._resources["fonts"]["phonic"], color=blue prs["mw"], r.phonicFont, color=r.linkColor
) )
frag.setAudio(audio) frag.setAudio(audio)
line.addFragment(frag) line.addFragment(frag)
@@ -318,7 +264,7 @@ class Word:
for ins in entry["ins"]: for ins in entry["ins"]:
try: try:
frag = Fragment( frag = Fragment(
ins["il"], self._resources["fonts"]["text"], color=base ins["il"], r.textFont, color=r.baseColor
) )
line.addFragment(frag) line.addFragment(frag)
space = " " space = " "
@@ -326,8 +272,8 @@ class Word:
pass pass
frag = Fragment( frag = Fragment(
space + ins["if"], space + ins["if"],
self._resources["fonts"]["bold"], r.boldFont,
color=base, color=r.baseColor
) )
line.addFragment(frag) line.addFragment(frag)
space = "; " space = "; "
@@ -336,8 +282,8 @@ class Word:
line = Line() line = Line()
frag = Fragment( frag = Fragment(
"; ".join(entry["lbs"]), "; ".join(entry["lbs"]),
self._resources["fonts"]["bold"], r.boldFont,
color=base, color=r.baseColor
) )
line.addFragment(frag) line.addFragment(frag)
lines.append(line) lines.append(line)
@@ -345,13 +291,13 @@ class Word:
for k, v in value.items(): for k, v in value.items():
if k == "sseq": # has multiple 'senses' if k == "sseq": # has multiple 'senses'
for seq in v: for seq in v:
r = self.mw_seq(seq) rr = self.mw_seq(seq)
lines += r lines += rr
elif k == "vd": elif k == "vd":
line = Line() line = Line()
line.addFragment( line.addFragment(
Fragment( Fragment(
v, self._resources["fonts"]["italic"], color=blue v, r.italicFont, color=r.linkColor
) )
) )
lines.append(line) lines.append(line)
@@ -361,7 +307,7 @@ class Word:
# #
# Create the header, base word and its label # Create the header, base word and its label
# #
word = self.current["hwi"]["hw"] word = self.current['definition']["hwi"]["hw"]
label = self.current["fl"] label = self.current["fl"]
html = f'<h1 class="def-word">{word} <span class="def-label">{label}</span></h1>\n' html = f'<h1 class="def-word">{word} <span class="def-label">{label}</span></h1>\n'
@@ -383,7 +329,7 @@ class Word:
if "prs" in self.current["hwi"].keys(): if "prs" in self.current["hwi"].keys():
tmp = [] tmp = []
for prs in self.current["hwi"]["prs"]: for prs in self.current["hwi"]["prs"]:
url = self.mw_sound_url(prs) url = QUrl()
how = prs["mw"] how = prs["mw"]
if url: if url:
tmp.append(f'<a href="{url}">\\{how}\\</a>') tmp.append(f'<a href="{url}">\\{how}\\</a>')

View File

@@ -1,12 +1,12 @@
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, Literal, NamedTuple, NotRequired, TypedDict, cast from typing import Any, NamedTuple, NotRequired, TypedDict
from PyQt6.QtCore import QEventLoop, QUrl, Qt from PyQt6.QtCore import QEventLoop, QUrl, Qt
from PyQt6.QtGui import QColor, QFont
from PyQt6.QtNetwork import QNetworkRequest from PyQt6.QtNetwork import QNetworkRequest
from lib.words import Word from lib.utils import Resources
from lib.definition import Line, Fragment from lib.definition import Line, Fragment
registration = { registration = {
@@ -27,10 +27,6 @@ class VerbalIllustration(TypedDict):
t: str t: str
aq: str aq: str
class VerbalIllustrationTuple(NamedTuple):
type_: str # 'vis'
data: list[VerbalIllustration]
class Sound(TypedDict): class Sound(TypedDict):
audio: str audio: str
ref: str ref: str
@@ -38,12 +34,10 @@ class Sound(TypedDict):
class Pronunciation(TypedDict): class Pronunciation(TypedDict):
mw: str mw: str
l: str l: NotRequired[str]
l2: str l2: NotRequired[str]
pun: str pun: NotRequired[str]
sound: Sound sound: NotRequired[Sound]
class Meta(TypedDict): class Meta(TypedDict):
id: str id: str
@@ -56,12 +50,12 @@ class Meta(TypedDict):
class HeadWordInfo(TypedDict): class HeadWordInfo(TypedDict):
hw: str hw: str
prs: list[Pronunciation] prs: NotRequired[list[Pronunciation]]
class HeadWord(TypedDict): class HeadWord(TypedDict):
hw: str hw: str
prs: list[Pronunciation] prs: NotRequired[list[Pronunciation]]
psl: str psl: NotRequired[str]
class Variant(TypedDict): class Variant(TypedDict):
va: str va: str
@@ -109,34 +103,26 @@ class RunInWrap(TypedDict):
text: str text: str
vrs: list[Variant] vrs: list[Variant]
class Sense: class Sense(TypedDict):
dt: list[str] # not full dt: list[list] # not full
et: list[str] # not full et: NotRequired[list[str]]
ins: list[Inflection] ins: NotRequired[list[Inflection]]
lbs: list[str] lbs: NotRequired[list[str]]
prs: list[Pronunciation] prs: NotRequired[list[Pronunciation]]
sdsense: DividedSense sdsense: NotRequired[DividedSense]
sgram: str sgram: NotRequired[str]
sls: list[str] sls: NotRequired[list[str]]
sn: str sn: NotRequired[str]
vrs: list[Variant] vrs: NotRequired[list[Variant]]
class SenseSequence(TypedDict):
sense: Sense
sen: Sense
class Definition(TypedDict): class Definition(TypedDict):
sseq: list[SenseSequence] sseq: list[list[list[Any]]]
vd: str vd: NotRequired[str]
class Pair(TypedDict):
objType: str
obj: list[Sense]|Sense|str|list[VerbalIllustration]|list[Any]
class EntryX(TypedDict):
meta: Meta
hom: NotRequired[str]
hwi: HeadWordInfo
ahws: NotRequired[list[HeadWord]]
vrs: NotRequired[list[Variant]]
fl: str
def_: list[Definition]
Entry = TypedDict( Entry = TypedDict(
'Entry', 'Entry',
{ {
@@ -149,13 +135,29 @@ Entry = TypedDict(
'def': list[Definition], 'def': list[Definition],
} }
) )
class WordType(TypedDict):
word: str
source: str
definition: dict[str, Any]
def fetch(word:str) -> dict[str, Any]: def make_pairs(src: list[Any]) -> list[Pair]:
result:list[Pair] = []
iters = [iter(src)]*2
for entry in zip(*iters):
pair = { 'objType': entry[0],
'obj': entry[1],
}
pair = trycast(Pair, pair)
assert pair is not None
result.append(pair)
return result
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))
request.setUrl(url) request.setUrl(url)
request.setTransferTimeout(3000) request.setTransferTimeout(3000)
reply = Word._nam.get(request) reply = Resources.nam.get(request)
assert reply is not None assert reply is not None
loop = QEventLoop() loop = QEventLoop()
reply.finished.connect(loop.quit) reply.finished.connect(loop.quit)
@@ -195,16 +197,16 @@ def getFirstSound(definition: list[Entry]) -> QUrl:
return url return url
return QUrl() return QUrl()
def do_prs(prs: list[Pronunciation]) -> list[Fragment]: def do_prs(hwi: HeadWordInfo) -> list[Fragment]:
r = Resources()
frags: list[Fragment] = [] frags: list[Fragment] = []
font = trycast(QFont, Word._resources['fonts']['label']) font = r.labelFont
assert font is not None linkColor = r.linkColor
linkColor = trycast(QColor, Word._resources['colors']['link']) subduedColor = r.subduedColor
assert linkColor is not None
subduedColor = trycast(QColor, Word._resources['colors']['subdued'])
assert subduedColor is not None
for pr in prs: if 'prs' not in hwi:
return []
for pr in hwi['prs']:
if 'pun' in pr: if 'pun' in pr:
pun = pr['pun'] pun = pr['pun']
else: else:
@@ -216,6 +218,7 @@ def do_prs(prs: list[Pronunciation]) -> list[Fragment]:
frag = Fragment(pr['mw'], font, color=subduedColor) frag = Fragment(pr['mw'], font, color=subduedColor)
if 'sound' in pr: if 'sound' in pr:
frag.setAudio(soundUrl(pr['sound'])) frag.setAudio(soundUrl(pr['sound']))
frag.setColor(linkColor)
frags.append(frag) frags.append(frag)
if 'l2' in pr: if 'l2' in pr:
frags.append( frags.append(
@@ -223,38 +226,141 @@ def do_prs(prs: list[Pronunciation]) -> list[Fragment]:
) )
return frags return frags
def do_sense(sense: Sense|None) -> tuple[list[Fragment], list[Line]]:
if sense is None:
return ([],[])
lines: list[Line] = []
frags: list[Fragment] = []
r = Resources()
if 'sn' in sense:
sn = sense['sn']
else:
sn = ''
print(f'{sn}\n\n',json.dumps(sense['dt'], indent=2))
iters = [iter(sense['dt'])]*2
for pair in zip(*iters):
pair = trycast(tuple[str, Any], pair)
assert pair is not None
print(pair[0])
if pair[0] == 'text':
line = Line()
line.addFragment(
Fragment(pair[1], r.textFont, color=r.baseColor)
)
lines.append(line)
return (frags, lines)
def do_pseq(outer: int,
inner: int,
pseq: list[list[Pair]]| None ) -> tuple[list[Fragment], list[Line]]:
assert pseq is not None
lines: list[Line] = []
frags: list[Fragment] = []
for entry in pseq:
pairs = make_pairs(entry)
for pair in pairs:
if pair['objType'] == 'bs':
(newFrags, newLines) = do_sense(trycast(Sense, pair['obj']))
frags += newFrags
lines += newLines
elif pair['objType'] == 'sense':
(newFrags, newLines) = do_sense(trycast(Sense, pair['obj']))
frags += newFrags
lines += newLines
else:
raise Exception(f"Unknown object type {pair['objType']}")
return (frags, lines)
def do_sseq(sseq:list[list[list[Pair]]]) -> list[Line]:
lines: list[Line] = []
r = Resources()
for outer, item_o in enumerate(sseq):
line = Line()
line.addFragment(
Fragment(str(outer+1), r.boldFont, color=r.baseColor)
)
for inner, item_i in enumerate(item_o):
line.addFragment(
Fragment(chr(ord('a')+inner), r.boldFont, color=r.baseColor)
)
pairs = make_pairs(item_i)
for pair in pairs:
objType = pair['objType']
if objType == 'sense':
sense = trycast(Sense, pair['obj'])
(frags, newlines) = do_sense(sense)
for frag in frags:
line.addFragment(frag)
lines.append(line)
lines += newlines
elif objType == 'sen':
raise Exception(f"sen unimplimented")
elif objType == 'pseq':
pseq = trycast(list[list[Pair]], pair['obj'])
(frags, newlines) = do_pseq(inner, outer, trycast(list[list[Pair]], pair['obj']))
for frag in frags:
line.addFragment(frag)
lines.append(line)
lines += newlines
elif objType == 'bs':
raise Exception(f"bs unimplimented")
else:
raise Exception(f"Unknown object[{objType}] for \n{json.dumps(pair['obj'],indent=2)}")
return lines
def do_def(entry: Definition) -> list[Line]:
r = Resources()
lines: list[Line] = []
assert trycast(Definition, entry) is not None
if 'vd' in entry:
line = Line()
line.addFragment(
Fragment(entry['vd'], r.italicFont, color = r.linkColor)
)
lines.append(line)
#
# sseg is required
#
sseq = entry['sseq']
lines += do_sseq(sseq)
return lines
def getDef(definition: list[Entry]) -> list[Line]: def getDef(definition: list[Entry]) -> list[Line]:
lines = [] r = Resources()
lines:list[Line] = []
# #
# Pull the fonts for ease of use # Pull the fonts for ease of use
# #
headerFont = trycast(QFont, Word._resources['fonts']['header']) headerFont = r.headerFont
assert headerFont is not None textFont = r.textFont
textFont = trycast(QFont, Word._resources['fonts']['text']) labelFont = r.labelFont
assert textFont is not None
labelFont = trycast(QFont, Word._resources['fonts']['label'])
assert labelFont is not None
# #
# Pull the colors for ease of use # Pull the colors for ease of use
# #
baseColor = trycast(QColor, Word._resources['colors']['base']) baseColor = r.baseColor
assert baseColor is not None linkColor = r.linkColor
linkColor = trycast(QColor, Word._resources['colors']['link']) subduedColor = r.subduedColor
assert linkColor is not None
subduedColor = trycast(QColor, Word._resources['colors']['subdued'])
assert subduedColor is not None
# #
# 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'] id = definition[0]['meta']['id'].lower().split(':')[0]
id = ':'.split(id)[0].lower() uses: dict[str,int] = {}
for entry in definition: for entry in definition:
if entry['meta']['id'].lower() == id: testId = entry['meta']['id'].lower().split(':')[0]
if testId == id:
entries += 1 entries += 1
try:
uses[entry['fl']] = uses.get(entry['fl'], 0) + 1
except KeyError:
pass
used: dict[str, int] = {}
for k in uses.keys():
used[k] = 0
for count, entry in enumerate(definition): for count, entry in enumerate(definition):
if entry['meta']['id'].lower() != id: testId = entry['meta']['id'].lower().split(':')[0]
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
@@ -270,13 +376,16 @@ def getDef(definition: list[Entry]) -> list[Line]:
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, headerFont, color=baseColor))
if 'hom' in entry: if entries > 1:
frag = Fragment(f" {count + 1} of {entries} ", textFont, color= subduedColor)
if 'fl' in entry:
frag = Fragment(f"{count} of {entries} ", textFont, color=
frag.setBackground(QColor(Qt.GlobalColor.gray)) frag.setBackground(QColor(Qt.GlobalColor.gray))
line.addFragment(frag) line.addFragment(frag)
line.addFragment(Fragment(entry['fl'], labelFont, color=baseColor)) if 'fl' in entry:
text = entry['fl']
used[text] += 1
if uses[text] > 1:
text += f' ({used[text]})'
line.addFragment(Fragment(text, labelFont, color=baseColor))
lines.append(line) lines.append(line)
# #
@@ -284,11 +393,15 @@ def getDef(definition: list[Entry]) -> list[Line]:
# While 'prs' is optional, the headword is not. This gets us what we want. # While 'prs' is optional, the headword is not. This gets us what we want.
# #
line = Line() line = Line()
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 + ' ', textFont, color=subduedColor))
for frag in do_prs(hwi['prs']): for frag in do_prs(hwi):
line.addFragment(frag) line.addFragment(frag)
if len(line.getLine()) > 0:
# lines.append(line)
# Try for defines = trycast(list[Definition], entry['def'])
return [Line()] assert defines is not None
for define in defines:
lines += do_def(define)
return lines