Simplify footnote handling in writer classes

This commit is contained in:
Veronica Berglyd Olsen
2024-04-16 21:54:31 +02:00
parent 57f9a0a844
commit bdce0e12c7
6 changed files with 44 additions and 49 deletions
+1 -1
View File
@@ -1494,4 +1494,4 @@ def processComment(text: str) -> tuple[nwComment, str, str, int, int]:
if content and (clean := classifier.strip().lower()) in CLASSIFIERS: if content and (clean := classifier.strip().lower()) in CLASSIFIERS:
term = "ERR" if term and clean not in TERMS else term.strip() term = "ERR" if term and clean not in TERMS else term.strip()
return CLASSIFIERS[clean], term, content.strip(), text.find(".") + 1, text.find(":") + 1 return CLASSIFIERS[clean], term, content.strip(), text.find(".") + 1, text.find(":") + 1
return nwComment.PLAIN, "", check, 0, 0 return nwComment.IGNORE if text.startswith("%~") else nwComment.PLAIN, "", check, 0, 0
+10 -7
View File
@@ -94,7 +94,7 @@ class ToHtml(Tokenizer):
# Internals # Internals
self._trMap = {} self._trMap = {}
self._usedNotes = set() self._usedNotes: dict[str, int] = {}
self.setReplaceUnicode(False) self.setReplaceUnicode(False)
return return
@@ -313,9 +313,9 @@ class ToHtml(Tokenizer):
lines = [] lines = []
lines.append(f"<h3>{footnotes}</h3>\n") lines.append(f"<h3>{footnotes}</h3>\n")
lines.append("<ol>\n") lines.append("<ol>\n")
for key, (index, content) in self._footnotes.items(): for key, index in self._usedNotes.items():
if key in self._usedNotes: if content := self._footnotes.get(key):
text = "</p><p>".join(self._formatText(t, f, tags) for t, f in content) text = self._formatText(*content, tags)
lines.append(f"<li id='footnote_{index}'><p>{text}</p></li>\n") lines.append(f"<li id='footnote_{index}'><p>{text}</p></li>\n")
lines.append("</ol>\n") lines.append("</ol>\n")
@@ -482,9 +482,12 @@ class ToHtml(Tokenizer):
for pos, fmt, data in reversed(tFmt): for pos, fmt, data in reversed(tFmt):
html = "" html = ""
if fmt == self.FMT_FNOTE: if fmt == self.FMT_FNOTE:
self._usedNotes.add(data) if data in self._footnotes:
index = self._footnotes.get(data, (0, ""))[0] or "ERR" index = len(self._usedNotes) + 1
html = f"<sup><a href='#footnote_{index}'>[{index}]</a></sup>" self._usedNotes[data] = index
html = f"<sup><a href='#footnote_{index}'>{index}</a></sup>"
else:
html = "<sup>ERR</sup>"
else: else:
html = tags.get(fmt, "ERR") html = tags.get(fmt, "ERR")
temp = f"{temp[:pos]}{html}{temp[pos:]}" temp = f"{temp[:pos]}{html}{temp[pos:]}"
+2 -4
View File
@@ -49,7 +49,7 @@ ESCAPES = {r"\*": "*", r"\~": "~", r"\_": "_", r"\[": "[", r"\]": "]", r"\ ": ""
RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL) RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL)
T_Formats = list[tuple[int, int, str]] T_Formats = list[tuple[int, int, str]]
T_Comment = tuple[int, list[tuple[str, T_Formats]]] T_Comment = tuple[str, T_Formats]
def stripEscape(text: str) -> str: def stripEscape(text: str) -> str:
@@ -561,9 +561,7 @@ class Tokenizer(ABC):
tmpMarkdown.append(f"{aLine}\n") tmpMarkdown.append(f"{aLine}\n")
elif cStyle == nwComment.FOOTNOTE: elif cStyle == nwComment.FOOTNOTE:
tLine, tFmt = self._extractFormats(cText, skip=self.FMT_FNOTE) tLine, tFmt = self._extractFormats(cText, skip=self.FMT_FNOTE)
if cKey not in self._footnotes: self._footnotes[cKey] = (tLine, tFmt)
self._footnotes[cKey] = (len(self._footnotes) + 1, [])
self._footnotes[cKey][1].append((tLine, tFmt))
else: else:
tLine, tFmt = self._extractFormats(cText) tLine, tFmt = self._extractFormats(cText)
self._tokens.append(( self._tokens.append((
+10 -8
View File
@@ -89,7 +89,7 @@ class ToMarkdown(Tokenizer):
self._genMode = self.M_STD self._genMode = self.M_STD
self._fullMD: list[str] = [] self._fullMD: list[str] = []
self._preserveBreaks = True self._preserveBreaks = True
self._usedNotes = set() self._usedNotes: dict[str, int] = {}
return return
## ##
@@ -208,11 +208,10 @@ class ToMarkdown(Tokenizer):
lines = [] lines = []
lines.append(f"### {footnotes}\n\n") lines.append(f"### {footnotes}\n\n")
for key, (index, content) in self._footnotes.items(): for key, index in self._usedNotes.items():
if key in self._usedNotes: if content := self._footnotes.get(key):
marker = f"{index}. " marker = f"{index}. "
indent = "\n\n"+" "*len(marker) text = self._formatText(*content, tags)
text = indent.join(self._formatText(t, f, tags) for t, f in content)
lines.append(f"{marker}{text}\n") lines.append(f"{marker}{text}\n")
lines.append("\n") lines.append("\n")
@@ -247,9 +246,12 @@ class ToMarkdown(Tokenizer):
for pos, fmt, data in reversed(tFmt): for pos, fmt, data in reversed(tFmt):
md = "" md = ""
if fmt == self.FMT_FNOTE: if fmt == self.FMT_FNOTE:
self._usedNotes.add(data) if data in self._footnotes:
index = self._footnotes.get(data, (0, ""))[0] or "ERR" index = len(self._usedNotes) + 1
md = f"[{index}]" self._usedNotes[data] = index
md = f"[{index}]"
else:
md = "[ERR]"
else: else:
md = tags.get(fmt, "") md = tags.get(fmt, "")
temp = f"{temp[:pos]}{md}{temp[pos:]}" temp = f"{temp[:pos]}{md}{temp[pos:]}"
+14 -23
View File
@@ -30,7 +30,6 @@ import logging
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from collections.abc import Sequence from collections.abc import Sequence
from copy import deepcopy
from datetime import datetime from datetime import datetime
from hashlib import sha256 from hashlib import sha256
from pathlib import Path from pathlib import Path
@@ -412,7 +411,6 @@ class ToOdt(Tokenizer):
def doConvert(self) -> None: def doConvert(self) -> None:
"""Convert the list of text tokens into XML elements.""" """Convert the list of text tokens into XML elements."""
self._result = "" # Not used, but cleared just in case self._result = "" # Not used, but cleared just in case
self._preProcessNotes()
pFmt: list[T_Formats] = [] pFmt: list[T_Formats] = []
pText = [] pText = []
@@ -687,7 +685,9 @@ class ToOdt(Tokenizer):
elif fFmt == self.FMT_SUB_E: elif fFmt == self.FMT_SUB_E:
xFmt &= M_SUB xFmt &= M_SUB
elif fFmt == self.FMT_FNOTE: elif fFmt == self.FMT_FNOTE:
parProc.appendNode(self._etNotes.get(fData)) parProc.appendNode(self._generateFootnote(fData))
elif fFmt == self.FMT_STRIP:
pass
else: else:
pErr += 1 pErr += 1
@@ -758,16 +758,11 @@ class ToOdt(Tokenizer):
return style.name return style.name
def _preProcessNotes(self) -> None: def _generateFootnote(self, key: str) -> ET.Element | None:
"""Generate XML elements for footnotes.""" """Generate a footnote XML object."""
fStyle = ODTParagraphStyle("New") if content := self._footnotes.get(key):
sStyle = ODTParagraphStyle("New")
sStyle.setTextIndent("0.000cm")
sStyle.setMarginLeft(self._mLeftFoot)
update = [key for key in self._footnotes.keys() if key not in self._etNotes]
for key in update:
cStyle = fStyle
self._nNote += 1 self._nNote += 1
nStyle = ODTParagraphStyle("New")
xNote = ET.Element(_mkTag("text", "note"), attrib={ xNote = ET.Element(_mkTag("text", "note"), attrib={
_mkTag("text", "id"): f"ftn{self._nNote}", _mkTag("text", "id"): f"ftn{self._nNote}",
_mkTag("text", "note-class"): "footnote", _mkTag("text", "note-class"): "footnote",
@@ -775,11 +770,9 @@ class ToOdt(Tokenizer):
xCite = ET.SubElement(xNote, _mkTag("text", "note-citation")) xCite = ET.SubElement(xNote, _mkTag("text", "note-citation"))
xCite.text = str(self._nNote) xCite.text = str(self._nNote)
xBody = ET.SubElement(xNote, _mkTag("text", "note-body")) xBody = ET.SubElement(xNote, _mkTag("text", "note-body"))
for text, fmt in self._footnotes[key][1]: self._addTextPar(xBody, "Footnote", nStyle, content[0], tFmt=content[1])
self._addTextPar(xBody, "Footnote", cStyle, text, tFmt=fmt) return xNote
cStyle = sStyle return None
self._etNotes[key] = xNote
return
def _emToCm(self, value: float) -> str: def _emToCm(self, value: float) -> str:
"""Converts an em value to centimetres.""" """Converts an em value to centimetres."""
@@ -1584,16 +1577,14 @@ class XMLParagraph:
def appendNode(self, xNode: ET.Element | None) -> None: def appendNode(self, xNode: ET.Element | None) -> None:
"""Append an XML node to the paragraph.""" """Append an XML node to the paragraph."""
if xNode: if xNode:
# We must make a copy in case the node is reused
xCopy = deepcopy(xNode)
if self._nState in (X_ROOT_TEXT, X_ROOT_TAIL): if self._nState in (X_ROOT_TEXT, X_ROOT_TAIL):
self._xRoot.append(xCopy) self._xRoot.append(xNode)
self._xTail = xCopy self._xTail = xNode
self._xTail.tail = "" self._xTail.tail = ""
self._nState = X_ROOT_TAIL self._nState = X_ROOT_TAIL
elif self._nState in (X_SPAN_TEXT, X_SPAN_SING): elif self._nState in (X_SPAN_TEXT, X_SPAN_SING):
self._xTail.append(xCopy) self._xTail.append(xNode)
self._xSing = xCopy self._xSing = xNode
self._xSing.tail = "" self._xSing.tail = ""
self._nState = X_SPAN_SING self._nState = X_SPAN_SING
return return
+7 -6
View File
@@ -65,12 +65,13 @@ class nwItemLayout(Enum):
class nwComment(Enum): class nwComment(Enum):
PLAIN = 0 PLAIN = 0
SYNOPSIS = 1 IGNORE = 1
SHORT = 2 SYNOPSIS = 2
NOTE = 3 SHORT = 3
FOOTNOTE = 4 NOTE = 4
COMMENT = 5 FOOTNOTE = 5
STORY = 6 COMMENT = 6
STORY = 7
# END Enum nwComment # END Enum nwComment