Process comments in the Tokenizer
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
"Short Description": "Short Description",
|
||||
"Footnotes": "Footnotes",
|
||||
"Comment": "Comment",
|
||||
"Notes": "Notes",
|
||||
"Note": "Note",
|
||||
"Tag": "Tag",
|
||||
"Point of View": "Point of View",
|
||||
"Focus": "Focus",
|
||||
|
||||
@@ -84,12 +84,14 @@ class TextFmt(IntEnum):
|
||||
SUP_E = 12 # End superscript
|
||||
SUB_B = 13 # Begin subscript
|
||||
SUB_E = 14 # End subscript
|
||||
DL_B = 15 # Begin dialogue
|
||||
DL_E = 16 # End dialogue
|
||||
ADL_B = 17 # Begin alt dialogue
|
||||
ADL_E = 18 # End alt dialogue
|
||||
FNOTE = 19 # Footnote marker
|
||||
STRIP = 20 # Strip the format code
|
||||
COL_B = 15 # Begin colour
|
||||
COL_E = 16 # End colour
|
||||
DL_B = 17 # Begin dialogue
|
||||
DL_E = 18 # End dialogue
|
||||
ADL_B = 19 # Begin alt dialogue
|
||||
ADL_E = 20 # End alt dialogue
|
||||
FNOTE = 21 # Footnote marker
|
||||
STRIP = 22 # Strip the format code
|
||||
|
||||
|
||||
class BlockTyp(IntEnum):
|
||||
@@ -98,19 +100,19 @@ class BlockTyp(IntEnum):
|
||||
An enum indicating the type of a text block.
|
||||
"""
|
||||
|
||||
EMPTY = 1 # Empty line (new paragraph)
|
||||
SYNOPSIS = 2 # Synopsis comment
|
||||
SHORT = 3 # Short description comment
|
||||
COMMENT = 4 # Comment line
|
||||
KEYWORD = 5 # Command line
|
||||
TITLE = 6 # Title
|
||||
HEAD1 = 7 # Heading 1
|
||||
HEAD2 = 8 # Heading 2
|
||||
HEAD3 = 9 # Heading 3
|
||||
HEAD4 = 10 # Heading 4
|
||||
TEXT = 11 # Text line
|
||||
SEP = 12 # Scene separator
|
||||
SKIP = 13 # Paragraph break
|
||||
EMPTY = 1 # Empty line (new paragraph)
|
||||
TITLE = 2 # Title
|
||||
HEAD1 = 3 # Heading 1
|
||||
HEAD2 = 4 # Heading 2
|
||||
HEAD3 = 5 # Heading 3
|
||||
HEAD4 = 6 # Heading 4
|
||||
TEXT = 7 # Text line
|
||||
SEP = 8 # Scene separator
|
||||
SKIP = 9 # Paragraph break
|
||||
SUMMARY = 10 # Synopsis/short comment
|
||||
NOTE = 11 # Note
|
||||
COMMENT = 12 # Comment
|
||||
KEYWORD = 13 # Tag/reference keywords
|
||||
|
||||
|
||||
class BlockFmt(Flag):
|
||||
|
||||
@@ -95,8 +95,9 @@ X_UND = 0x008 # Underline format
|
||||
X_MRK = 0x010 # Marked format
|
||||
X_SUP = 0x020 # Superscript
|
||||
X_SUB = 0x040 # Subscript
|
||||
X_DLG = 0x080 # Dialogue
|
||||
X_DLA = 0x100 # Alt. Dialogue
|
||||
X_COL = 0x080 # Coloured text
|
||||
X_DLG = 0x100 # Dialogue
|
||||
X_DLA = 0x200 # Alt. Dialogue
|
||||
|
||||
# Formatting Masks
|
||||
M_BLD = ~X_BLD
|
||||
@@ -106,6 +107,7 @@ M_UND = ~X_UND
|
||||
M_MRK = ~X_MRK
|
||||
M_SUP = ~X_SUP
|
||||
M_SUB = ~X_SUB
|
||||
M_COL = ~X_COL
|
||||
M_DLG = ~X_DLG
|
||||
M_DLA = ~X_DLA
|
||||
|
||||
@@ -214,6 +216,7 @@ class ToDocX(Tokenizer):
|
||||
|
||||
def initDocument(self) -> None:
|
||||
"""Initialises the DocX document structure."""
|
||||
super().initDocument()
|
||||
self._fontFamily = self._textFont.family()
|
||||
self._fontSize = self._textFont.pointSizeF()
|
||||
self._generateStyles()
|
||||
@@ -289,17 +292,8 @@ class ToDocX(Tokenizer):
|
||||
elif tType == BlockTyp.SKIP:
|
||||
self._processFragments(par, S_NORM, "")
|
||||
|
||||
elif tType == BlockTyp.SYNOPSIS and self._doSynopsis:
|
||||
tTemp, tFmt = self._formatSynopsis(tText, tFormat, True)
|
||||
self._processFragments(par, S_META, tTemp, tFmt)
|
||||
|
||||
elif tType == BlockTyp.SHORT and self._doSynopsis:
|
||||
tTemp, tFmt = self._formatSynopsis(tText, tFormat, False)
|
||||
self._processFragments(par, S_META, tTemp, tFmt)
|
||||
|
||||
elif tType == BlockTyp.COMMENT and self._doComments:
|
||||
tTemp, tFmt = self._formatComments(tText, tFormat)
|
||||
self._processFragments(par, S_META, tTemp, tFmt)
|
||||
elif tType in self.L_NOTES:
|
||||
self._processFragments(par, S_META, tText, tFormat)
|
||||
|
||||
elif tType == BlockTyp.KEYWORD and self._doKeywords:
|
||||
tTemp, tFmt = self._formatKeywords(tText)
|
||||
@@ -379,24 +373,6 @@ class ToDocX(Tokenizer):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _formatSynopsis(self, text: str, fmt: T_Formats, synopsis: bool) -> tuple[str, T_Formats]:
|
||||
"""Apply formatting to synopsis lines."""
|
||||
name = self._localLookup("Synopsis" if synopsis else "Short Description")
|
||||
shift = len(name) + 2
|
||||
rTxt = f"{name}: {text}"
|
||||
rFmt: T_Formats = [(0, TextFmt.B_B, ""), (len(name) + 1, TextFmt.B_E, "")]
|
||||
rFmt.extend((p + shift, f, d) for p, f, d in fmt)
|
||||
return rTxt, rFmt
|
||||
|
||||
def _formatComments(self, text: str, fmt: T_Formats) -> tuple[str, T_Formats]:
|
||||
"""Apply formatting to comments."""
|
||||
name = self._localLookup("Comment")
|
||||
shift = len(name) + 2
|
||||
rTxt = f"{name}: {text}"
|
||||
rFmt: T_Formats = [(0, TextFmt.B_B, ""), (len(name) + 1, TextFmt.B_E, "")]
|
||||
rFmt.extend((p + shift, f, d) for p, f, d in fmt)
|
||||
return rTxt, rFmt
|
||||
|
||||
def _formatKeywords(self, text: str) -> tuple[str, T_Formats]:
|
||||
"""Apply formatting to keywords."""
|
||||
valid, bits, _ = self._project.index.scanThis("@"+text)
|
||||
@@ -421,6 +397,7 @@ class ToDocX(Tokenizer):
|
||||
xFmt = 0x00
|
||||
xNode = None
|
||||
fStart = 0
|
||||
fClass = ""
|
||||
for fPos, fFmt, fData in tFmt or []:
|
||||
|
||||
if xNode is not None:
|
||||
@@ -428,7 +405,7 @@ class ToDocX(Tokenizer):
|
||||
xNode = None
|
||||
|
||||
if temp := text[fStart:fPos]:
|
||||
par.addContent(self._textRunToXml(temp, xFmt))
|
||||
par.addContent(self._textRunToXml(temp, xFmt, fClass))
|
||||
|
||||
if fFmt == TextFmt.B_B:
|
||||
xFmt |= X_BLD
|
||||
@@ -458,6 +435,12 @@ class ToDocX(Tokenizer):
|
||||
xFmt |= X_SUB
|
||||
elif fFmt == TextFmt.SUB_E:
|
||||
xFmt &= M_SUB
|
||||
elif fFmt == TextFmt.COL_B:
|
||||
xFmt |= X_COL
|
||||
fClass = fData
|
||||
elif fFmt == TextFmt.COL_E:
|
||||
xFmt &= M_COL
|
||||
fClass = ""
|
||||
elif fFmt == TextFmt.DL_B:
|
||||
xFmt |= X_DLG
|
||||
elif fFmt == TextFmt.DL_E:
|
||||
@@ -478,33 +461,35 @@ class ToDocX(Tokenizer):
|
||||
par.addContent(xNode)
|
||||
|
||||
if temp := text[fStart:]:
|
||||
par.addContent(self._textRunToXml(temp, xFmt))
|
||||
par.addContent(self._textRunToXml(temp, xFmt, fClass))
|
||||
|
||||
return
|
||||
|
||||
def _textRunToXml(self, text: str, fmt: int) -> ET.Element:
|
||||
def _textRunToXml(self, text: str, fmt: int, fClass: str = "") -> ET.Element:
|
||||
"""Encode the text run into XML."""
|
||||
run = ET.Element(_wTag("r"))
|
||||
rPr = xmlSubElem(run, _wTag("rPr"))
|
||||
if fmt & X_BLD == X_BLD:
|
||||
if fmt & X_BLD:
|
||||
xmlSubElem(rPr, _wTag("b"))
|
||||
if fmt & X_ITA == X_ITA:
|
||||
if fmt & X_ITA:
|
||||
xmlSubElem(rPr, _wTag("i"))
|
||||
if fmt & X_UND == X_UND:
|
||||
if fmt & X_UND:
|
||||
xmlSubElem(rPr, _wTag("u"), attrib={_wTag("val"): "single"})
|
||||
if fmt & X_MRK == X_MRK:
|
||||
if fmt & X_MRK:
|
||||
xmlSubElem(rPr, _wTag("shd"), attrib={
|
||||
_wTag("fill"): COL_MARK_TXT, _wTag("val"): "clear",
|
||||
})
|
||||
if fmt & X_DEL == X_DEL:
|
||||
if fmt & X_DEL:
|
||||
xmlSubElem(rPr, _wTag("strike"))
|
||||
if fmt & X_SUP == X_SUP:
|
||||
if fmt & X_SUP:
|
||||
xmlSubElem(rPr, _wTag("vertAlign"), attrib={_wTag("val"): "superscript"})
|
||||
if fmt & X_SUB == X_SUB:
|
||||
if fmt & X_SUB:
|
||||
xmlSubElem(rPr, _wTag("vertAlign"), attrib={_wTag("val"): "subscript"})
|
||||
if fmt & X_DLG == X_DLG:
|
||||
if fmt & X_COL and (color := self._classes.get(fClass)):
|
||||
xmlSubElem(rPr, _wTag("color"), attrib={_wTag("val"): _docXCol(color)})
|
||||
if fmt & X_DLG:
|
||||
xmlSubElem(rPr, _wTag("color"), attrib={_wTag("val"): COL_DIALOG_M})
|
||||
if fmt & X_DLA == X_DLA:
|
||||
if fmt & X_DLA:
|
||||
xmlSubElem(rPr, _wTag("color"), attrib={_wTag("val"): COL_DIALOG_A})
|
||||
|
||||
for segment in RX_TEXT.split(text):
|
||||
@@ -659,7 +644,6 @@ class ToDocX(Tokenizer):
|
||||
before=fSz * self._marginMeta[0],
|
||||
after=fSz * self._marginMeta[1],
|
||||
line=fSz * self._lineHeight,
|
||||
color=COL_META_TXT,
|
||||
))
|
||||
|
||||
# Header
|
||||
|
||||
@@ -251,14 +251,11 @@ class ToHtml(Tokenizer):
|
||||
elif tType == BlockTyp.SKIP:
|
||||
lines.append(f"<p class='skip'{hStyle}> </p>\n")
|
||||
|
||||
elif tType == BlockTyp.SYNOPSIS and self._doSynopsis:
|
||||
lines.append(self._formatSynopsis(self._formatText(tText, tFormat), True))
|
||||
|
||||
elif tType == BlockTyp.SHORT and self._doSynopsis:
|
||||
lines.append(self._formatSynopsis(self._formatText(tText, tFormat), False))
|
||||
elif tType == BlockTyp.SUMMARY:
|
||||
lines.append(f"<p class='synopsis'>{self._formatText(tText, tFormat)}</p>\n")
|
||||
|
||||
elif tType == BlockTyp.COMMENT and self._doComments:
|
||||
lines.append(self._formatComments(self._formatText(tText, tFormat)))
|
||||
lines.append(f"<p class='comment'>{self._formatText(tText, tFormat)}</p>\n")
|
||||
|
||||
elif tType == BlockTyp.KEYWORD and self._doKeywords:
|
||||
tag, text = self._formatKeywords(tText)
|
||||
@@ -499,19 +496,6 @@ class ToHtml(Tokenizer):
|
||||
|
||||
return stripEscape(temp)
|
||||
|
||||
def _formatSynopsis(self, text: str, synopsis: bool) -> str:
|
||||
"""Apply HTML formatting to synopsis."""
|
||||
if synopsis:
|
||||
sSynop = self._localLookup("Synopsis")
|
||||
else:
|
||||
sSynop = self._localLookup("Short Description")
|
||||
return f"<p class='synopsis'><strong>{sSynop}:</strong> {text}</p>\n"
|
||||
|
||||
def _formatComments(self, text: str) -> str:
|
||||
"""Apply HTML formatting to comments."""
|
||||
sComm = self._localLookup("Comment")
|
||||
return f"<p class='comment'><strong>{sComm}:</strong> {text}</p>\n"
|
||||
|
||||
def _formatKeywords(self, text: str) -> tuple[str, str]:
|
||||
"""Apply HTML formatting to keywords."""
|
||||
valid, bits, _ = self._project.index.scanThis("@"+text)
|
||||
|
||||
@@ -32,9 +32,10 @@ from abc import ABC, abstractmethod
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import NamedTuple
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
from PyQt5.QtGui import QFont
|
||||
from PyQt5.QtGui import QColor, QFont
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.common import checkInt, formatTimeStamp, numberToRoman
|
||||
@@ -52,6 +53,26 @@ from novelwriter.text.patterns import REGEX_PATTERNS
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ComStyle(NamedTuple):
|
||||
|
||||
label: str = ""
|
||||
labelClass: str = ""
|
||||
textClass: str = ""
|
||||
blockType: BlockTyp = BlockTyp.TEXT
|
||||
|
||||
|
||||
COMMENT_STYLE = {
|
||||
nwComment.PLAIN: ComStyle("Comment", "comment", "comment", BlockTyp.COMMENT),
|
||||
nwComment.IGNORE: ComStyle(),
|
||||
nwComment.SYNOPSIS: ComStyle("Synopsis", "modifier", "synopsis", BlockTyp.SUMMARY),
|
||||
nwComment.SHORT: ComStyle("Short Description", "modifier", "synopsis", BlockTyp.SUMMARY),
|
||||
nwComment.NOTE: ComStyle("Note", "modifier", "note", BlockTyp.NOTE),
|
||||
nwComment.FOOTNOTE: ComStyle("", "modifier", "note"),
|
||||
nwComment.COMMENT: ComStyle(),
|
||||
nwComment.STORY: ComStyle("", "modifier", "note", BlockTyp.NOTE),
|
||||
}
|
||||
|
||||
|
||||
class Tokenizer(ABC):
|
||||
"""Core: Text Tokenizer Abstract Base Class
|
||||
|
||||
@@ -72,7 +93,7 @@ class Tokenizer(ABC):
|
||||
BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD2, BlockTyp.HEAD3,
|
||||
BlockTyp.HEAD4, BlockTyp.SEP, BlockTyp.SKIP,
|
||||
]
|
||||
L_SUMMARY = [BlockTyp.SYNOPSIS, BlockTyp.SHORT]
|
||||
L_NOTES = [BlockTyp.SUMMARY, BlockTyp.NOTE, BlockTyp.COMMENT]
|
||||
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
|
||||
@@ -114,6 +135,7 @@ class Tokenizer(ABC):
|
||||
|
||||
# Other Setting
|
||||
self._theme = TextDocumentTheme()
|
||||
self._classes: dict[str, QColor] = {}
|
||||
|
||||
# Margins
|
||||
self._marginTitle = nwStyles.T_MARGIN["H0"]
|
||||
@@ -433,6 +455,13 @@ class Tokenizer(ABC):
|
||||
def saveDocument(self, path: Path) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
def initDocument(self) -> None:
|
||||
"""Initialise data after settings."""
|
||||
self._classes["modifier"] = self._theme.modifier
|
||||
self._classes["synopsis"] = self._theme.note
|
||||
self._classes["comment"] = self._theme.comment
|
||||
return
|
||||
|
||||
def addRootHeading(self, tHandle: str) -> None:
|
||||
"""Add a heading at the start of a new root folder."""
|
||||
self._text = ""
|
||||
@@ -569,36 +598,29 @@ class Tokenizer(ABC):
|
||||
if aLine.startswith("%~"):
|
||||
continue
|
||||
|
||||
cStyle, cKey, cText, _, _ = processComment(aLine)
|
||||
if cStyle in (nwComment.SYNOPSIS, nwComment.SHORT) and not self._doSynopsis:
|
||||
continue
|
||||
if cStyle == nwComment.PLAIN and not self._doComments:
|
||||
continue
|
||||
|
||||
if self._doJustify and not sAlign & self.M_ALIGNED:
|
||||
sAlign |= BlockFmt.JUSTIFY
|
||||
|
||||
cStyle, cKey, cText, _, _ = processComment(aLine)
|
||||
if cStyle == nwComment.SYNOPSIS:
|
||||
tLine, tFmt = self._extractFormats(cText)
|
||||
blocks.append((
|
||||
BlockTyp.SYNOPSIS, nHead, tLine, tFmt, sAlign
|
||||
))
|
||||
if self._doSynopsis and self._keepRaw:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
elif cStyle == nwComment.SHORT:
|
||||
tLine, tFmt = self._extractFormats(cText)
|
||||
blocks.append((
|
||||
BlockTyp.SHORT, nHead, tLine, tFmt, sAlign
|
||||
))
|
||||
if self._doSynopsis and self._keepRaw:
|
||||
if cStyle in (nwComment.SYNOPSIS, nwComment.SHORT, nwComment.PLAIN):
|
||||
bStyle = COMMENT_STYLE[cStyle]
|
||||
tLine, tFmt = self._formatNote(bStyle, cKey, cText)
|
||||
blocks.append((bStyle.blockType, nHead, tLine, tFmt, sAlign))
|
||||
if self._keepRaw:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
|
||||
elif cStyle == nwComment.FOOTNOTE:
|
||||
tLine, tFmt = self._extractFormats(cText, skip=TextFmt.FNOTE)
|
||||
self._footnotes[f"{tHandle}:{cKey}"] = (tLine, tFmt)
|
||||
if self._keepRaw:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
else:
|
||||
tLine, tFmt = self._extractFormats(cText)
|
||||
blocks.append((
|
||||
BlockTyp.COMMENT, nHead, tLine, tFmt, sAlign
|
||||
))
|
||||
if self._doComments and self._keepRaw:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
continue
|
||||
|
||||
elif aLine.startswith("@"):
|
||||
# Keywords
|
||||
@@ -992,25 +1014,10 @@ class Tokenizer(ABC):
|
||||
allChars += nChars
|
||||
allWordChars += nWChars
|
||||
|
||||
elif tType == BlockTyp.SYNOPSIS and self._doSynopsis:
|
||||
text = "{0}: {1}".format(self._localLookup("Synopsis"), tText)
|
||||
words = text.split()
|
||||
elif tType in self.L_NOTES:
|
||||
words = tText.split()
|
||||
allWords += len(words)
|
||||
allChars += len(text)
|
||||
allWordChars += len("".join(words))
|
||||
|
||||
elif tType == BlockTyp.SHORT and self._doSynopsis:
|
||||
text = "{0}: {1}".format(self._localLookup("Short Description"), tText)
|
||||
words = text.split()
|
||||
allWords += len(words)
|
||||
allChars += len(text)
|
||||
allWordChars += len("".join(words))
|
||||
|
||||
elif tType == BlockTyp.COMMENT and self._doComments:
|
||||
text = "{0}: {1}".format(self._localLookup("Comment"), tText)
|
||||
words = text.split()
|
||||
allWords += len(words)
|
||||
allChars += len(text)
|
||||
allChars += len(tText)
|
||||
allWordChars += len("".join(words))
|
||||
|
||||
elif tType == BlockTyp.KEYWORD and self._doKeywords:
|
||||
@@ -1071,6 +1078,21 @@ class Tokenizer(ABC):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _formatNote(self, style: ComStyle, key: str, text: str) -> tuple[str, T_Formats]:
|
||||
"""Apply formatting to comments and notes."""
|
||||
tTxt, tFmt = self._extractFormats(text)
|
||||
tFmt.insert(0, (0, TextFmt.COL_B, style.textClass))
|
||||
tFmt.append((len(tTxt), TextFmt.COL_E, ""))
|
||||
if label := (self._localLookup(style.label) + (f" ({key})" if key else "")).strip():
|
||||
shift = len(label) + 2
|
||||
tTxt = f"{label}: {tTxt}"
|
||||
rFmt = [(0, TextFmt.B_B, ""), (shift - 1, TextFmt.B_E, "")]
|
||||
if style.labelClass:
|
||||
rFmt.insert(1, (0, TextFmt.COL_B, style.labelClass))
|
||||
rFmt.append((shift - 1, TextFmt.COL_E, ""))
|
||||
rFmt.extend((p + shift, f, d) for p, f, d in tFmt)
|
||||
return tTxt, rFmt
|
||||
|
||||
def _extractFormats(
|
||||
self, text: str, skip: int = 0, hDialog: bool = False
|
||||
) -> tuple[str, T_Formats]:
|
||||
|
||||
@@ -150,17 +150,8 @@ class ToMarkdown(Tokenizer):
|
||||
elif tType == BlockTyp.SKIP:
|
||||
lines.append(f"{cSkip}\n\n")
|
||||
|
||||
elif tType == BlockTyp.SYNOPSIS and self._doSynopsis:
|
||||
label = self._localLookup("Synopsis")
|
||||
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
|
||||
|
||||
elif tType == BlockTyp.SHORT and self._doSynopsis:
|
||||
label = self._localLookup("Short Description")
|
||||
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
|
||||
|
||||
elif tType == BlockTyp.COMMENT and self._doComments:
|
||||
label = self._localLookup("Comment")
|
||||
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
|
||||
elif tType in self.L_NOTES:
|
||||
lines.append(f"{self._formatText(tText, tFormat, mTags)}\n\n")
|
||||
|
||||
elif tType == BlockTyp.KEYWORD and self._doKeywords:
|
||||
lines.append(self._formatKeywords(tText, tStyle))
|
||||
|
||||
@@ -90,8 +90,9 @@ X_UND = 0x008 # Underline format
|
||||
X_MRK = 0x010 # Marked format
|
||||
X_SUP = 0x020 # Superscript
|
||||
X_SUB = 0x040 # Subscript
|
||||
X_DLG = 0x080 # Dialogue
|
||||
X_DLA = 0x100 # Alt. Dialogue
|
||||
X_COL = 0x080 # Coloured text
|
||||
X_DLG = 0x100 # Dialogue
|
||||
X_DLA = 0x200 # Alt. Dialogue
|
||||
|
||||
# Formatting Masks
|
||||
M_BLD = ~X_BLD
|
||||
@@ -101,6 +102,7 @@ M_UND = ~X_UND
|
||||
M_MRK = ~X_MRK
|
||||
M_SUP = ~X_SUP
|
||||
M_SUB = ~X_SUB
|
||||
M_COL = ~X_COL
|
||||
M_DLG = ~X_DLG
|
||||
M_DLA = ~X_DLA
|
||||
|
||||
@@ -152,7 +154,7 @@ class ToOdt(Tokenizer):
|
||||
|
||||
self._mainPara: dict[str, ODTParagraphStyle] = {} # User-accessible paragraph styles
|
||||
self._autoPara: dict[str, ODTParagraphStyle] = {} # Auto-generated paragraph styles
|
||||
self._autoText: dict[int, ODTTextStyle] = {} # Auto-generated text styles
|
||||
self._autoText: dict[str, ODTTextStyle] = {} # Auto-generated text styles
|
||||
|
||||
# Footnotes
|
||||
self._nNote = 0
|
||||
@@ -264,6 +266,8 @@ class ToOdt(Tokenizer):
|
||||
|
||||
def initDocument(self) -> None:
|
||||
"""Initialises a new open document XML tree."""
|
||||
super().initDocument()
|
||||
|
||||
# Initialise Variables
|
||||
# ====================
|
||||
|
||||
@@ -480,17 +484,8 @@ class ToOdt(Tokenizer):
|
||||
elif tType == BlockTyp.SKIP:
|
||||
self._addTextPar(xText, S_TEXT, oStyle, "")
|
||||
|
||||
elif tType == BlockTyp.SYNOPSIS and self._doSynopsis:
|
||||
tTemp, tFmt = self._formatSynopsis(tText, tFormat, True)
|
||||
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
|
||||
|
||||
elif tType == BlockTyp.SHORT and self._doSynopsis:
|
||||
tTemp, tFmt = self._formatSynopsis(tText, tFormat, False)
|
||||
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
|
||||
|
||||
elif tType == BlockTyp.COMMENT and self._doComments:
|
||||
tTemp, tFmt = self._formatComments(tText, tFormat)
|
||||
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
|
||||
elif tType in self.L_NOTES:
|
||||
self._addTextPar(xText, S_META, oStyle, tText, tFmt=tFormat)
|
||||
|
||||
elif tType == BlockTyp.KEYWORD and self._doKeywords:
|
||||
tTemp, tFmt = self._formatKeywords(tText)
|
||||
@@ -562,24 +557,6 @@ class ToOdt(Tokenizer):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _formatSynopsis(self, text: str, fmt: T_Formats, synopsis: bool) -> tuple[str, T_Formats]:
|
||||
"""Apply formatting to synopsis lines."""
|
||||
name = self._localLookup("Synopsis" if synopsis else "Short Description")
|
||||
shift = len(name) + 2
|
||||
rTxt = f"{name}: {text}"
|
||||
rFmt: T_Formats = [(0, TextFmt.B_B, ""), (len(name) + 1, TextFmt.B_E, "")]
|
||||
rFmt.extend((p + shift, f, d) for p, f, d in fmt)
|
||||
return rTxt, rFmt
|
||||
|
||||
def _formatComments(self, text: str, fmt: T_Formats) -> tuple[str, T_Formats]:
|
||||
"""Apply formatting to comments."""
|
||||
name = self._localLookup("Comment")
|
||||
shift = len(name) + 2
|
||||
rTxt = f"{name}: {text}"
|
||||
rFmt: T_Formats = [(0, TextFmt.B_B, ""), (len(name) + 1, TextFmt.B_E, "")]
|
||||
rFmt.extend((p + shift, f, d) for p, f, d in fmt)
|
||||
return rTxt, rFmt
|
||||
|
||||
def _formatKeywords(self, text: str) -> tuple[str, T_Formats]:
|
||||
"""Apply formatting to keywords."""
|
||||
valid, bits, _ = self._project.index.scanThis("@"+text)
|
||||
@@ -630,6 +607,7 @@ class ToOdt(Tokenizer):
|
||||
tFrag = ""
|
||||
fLast = 0
|
||||
xNode = None
|
||||
fClass = ""
|
||||
for fPos, fFmt, fData in tFmt or []:
|
||||
|
||||
# Add any extra nodes
|
||||
@@ -642,7 +620,7 @@ class ToOdt(Tokenizer):
|
||||
if xFmt == 0x00:
|
||||
parProc.appendText(tFrag)
|
||||
else:
|
||||
parProc.appendSpan(tFrag, self._textStyle(xFmt))
|
||||
parProc.appendSpan(tFrag, self._textStyle(xFmt, fClass))
|
||||
|
||||
# Calculate the change of format
|
||||
if fFmt == TextFmt.B_B:
|
||||
@@ -673,6 +651,12 @@ class ToOdt(Tokenizer):
|
||||
xFmt |= X_SUB
|
||||
elif fFmt == TextFmt.SUB_E:
|
||||
xFmt &= M_SUB
|
||||
elif fFmt == TextFmt.COL_B:
|
||||
xFmt |= X_COL
|
||||
fClass = fData
|
||||
elif fFmt == TextFmt.COL_E:
|
||||
xFmt &= M_COL
|
||||
fClass = ""
|
||||
elif fFmt == TextFmt.DL_B:
|
||||
xFmt |= X_DLG
|
||||
elif fFmt == TextFmt.DL_E:
|
||||
@@ -697,7 +681,7 @@ class ToOdt(Tokenizer):
|
||||
if xFmt == 0x00:
|
||||
parProc.appendText(tFrag)
|
||||
else:
|
||||
parProc.appendSpan(tFrag, self._textStyle(xFmt))
|
||||
parProc.appendSpan(tFrag, self._textStyle(xFmt, fClass))
|
||||
|
||||
if pErr > 0:
|
||||
self._errData.append("Unknown format tag encountered")
|
||||
@@ -731,10 +715,14 @@ class ToOdt(Tokenizer):
|
||||
|
||||
return modStyle.name
|
||||
|
||||
def _textStyle(self, hFmt: int) -> str:
|
||||
def _textStyle(self, hFmt: int, fClass: str = "") -> str:
|
||||
"""Return a text style for a given style code."""
|
||||
if hFmt in self._autoText:
|
||||
return self._autoText[hFmt].name
|
||||
tKey = str(hFmt)
|
||||
if fClass and (color := self._classes.get(fClass)):
|
||||
tKey = f"{tKey}:{fClass}"
|
||||
|
||||
if tKey in self._autoText:
|
||||
return self._autoText[tKey].name
|
||||
|
||||
style = ODTTextStyle(f"T{len(self._autoText)+1:d}")
|
||||
if hFmt & X_BLD:
|
||||
@@ -747,18 +735,20 @@ class ToOdt(Tokenizer):
|
||||
if hFmt & X_UND:
|
||||
style.setUnderlineStyle("solid")
|
||||
style.setUnderlineWidth("auto")
|
||||
style.setUnderlineColour("font-color")
|
||||
style.setUnderlineColor("font-color")
|
||||
if hFmt & X_MRK:
|
||||
style.setBackgroundColour(self._markText)
|
||||
style.setBackgroundColor(self._markText)
|
||||
if hFmt & X_SUP:
|
||||
style.setTextPosition("super")
|
||||
if hFmt & X_SUB:
|
||||
style.setTextPosition("sub")
|
||||
if hFmt & X_DLG:
|
||||
style.setColour(self._colDialogM)
|
||||
if hFmt & X_DLA:
|
||||
style.setColour(self._colDialogA)
|
||||
self._autoText[hFmt] = style
|
||||
if hFmt & X_COL and color:
|
||||
style.setColor(color)
|
||||
# if hFmt & X_DLG:
|
||||
# style.setColour(self._colDialogM)
|
||||
# if hFmt & X_DLA:
|
||||
# style.setColour(self._colDialogA)
|
||||
self._autoText[tKey] = style
|
||||
|
||||
return style.name
|
||||
|
||||
@@ -923,7 +913,6 @@ class ToOdt(Tokenizer):
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeText)
|
||||
style.setFontWeight(self._fontWeight)
|
||||
style.setColour(self._theme.note)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
@@ -973,7 +962,7 @@ class ToOdt(Tokenizer):
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead1)
|
||||
style.setFontWeight(self._headWeight)
|
||||
style.setColour(hColor)
|
||||
style.setColor(hColor)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
@@ -990,7 +979,7 @@ class ToOdt(Tokenizer):
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead2)
|
||||
style.setFontWeight(self._headWeight)
|
||||
style.setColour(hColor)
|
||||
style.setColor(hColor)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
@@ -1007,7 +996,7 @@ class ToOdt(Tokenizer):
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead3)
|
||||
style.setFontWeight(self._headWeight)
|
||||
style.setColour(hColor)
|
||||
style.setColor(hColor)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
@@ -1024,7 +1013,7 @@ class ToOdt(Tokenizer):
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead4)
|
||||
style.setFontWeight(self._headWeight)
|
||||
style.setColour(hColor)
|
||||
style.setColor(hColor)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
@@ -1285,7 +1274,7 @@ class ODTParagraphStyle:
|
||||
self._tAttr["font-weight"][1] = None
|
||||
return
|
||||
|
||||
def setColour(self, value: QColor | None) -> None:
|
||||
def setColor(self, value: QColor | None) -> None:
|
||||
"""Set text colour."""
|
||||
if isinstance(value, QColor):
|
||||
self._tAttr["color"][1] = value.name(QColor.NameFormat.HexRgb)
|
||||
@@ -1393,15 +1382,15 @@ class ODTTextStyle:
|
||||
self._tAttr["font-style"][1] = None
|
||||
return
|
||||
|
||||
def setColour(self, value: str | None) -> None:
|
||||
def setColor(self, value: QColor | None) -> None:
|
||||
"""Set text colour."""
|
||||
if value and len(value) == 7 and value[0] == "#":
|
||||
self._tAttr["color"][1] = value
|
||||
if isinstance(value, QColor):
|
||||
self._tAttr["color"][1] = value.name(QColor.NameFormat.HexRgb)
|
||||
else:
|
||||
self._tAttr["color"][1] = None
|
||||
return
|
||||
|
||||
def setBackgroundColour(self, value: str | None) -> None:
|
||||
def setBackgroundColor(self, value: str | None) -> None:
|
||||
"""Set text background colour."""
|
||||
if value and len(value) == 7 and value[0] == "#":
|
||||
self._tAttr["background-color"][1] = value
|
||||
@@ -1449,7 +1438,7 @@ class ODTTextStyle:
|
||||
self._tAttr["text-underline-width"][1] = None
|
||||
return
|
||||
|
||||
def setUnderlineColour(self, value: str | None) -> None:
|
||||
def setUnderlineColor(self, value: str | None) -> None:
|
||||
"""Set text underline colour."""
|
||||
if value in self.VALID_LCOL:
|
||||
self._tAttr["text-underline-color"][1] = value
|
||||
|
||||
@@ -108,6 +108,8 @@ class ToQTextDocument(Tokenizer):
|
||||
|
||||
def initDocument(self) -> None:
|
||||
"""Initialise all computed values of the document."""
|
||||
super().initDocument()
|
||||
|
||||
self._document.setUndoRedoEnabled(False)
|
||||
self._document.blockSignals(True)
|
||||
self._document.clear()
|
||||
@@ -162,23 +164,9 @@ class ToQTextDocument(Tokenizer):
|
||||
self._cText.setBackground(QtTransparent)
|
||||
self._cText.setForeground(self._theme.text)
|
||||
|
||||
self._cComment = QTextCharFormat(self._cText)
|
||||
self._cComment.setForeground(self._theme.comment)
|
||||
|
||||
self._cCommentMod = QTextCharFormat(self._cText)
|
||||
self._cCommentMod.setForeground(self._theme.comment)
|
||||
self._cCommentMod.setFontWeight(self._bold)
|
||||
|
||||
self._cNote = QTextCharFormat(self._cText)
|
||||
self._cNote.setForeground(self._theme.note)
|
||||
|
||||
self._cCode = QTextCharFormat(self._cText)
|
||||
self._cCode.setForeground(self._theme.code)
|
||||
|
||||
self._cModifier = QTextCharFormat(self._cText)
|
||||
self._cModifier.setForeground(self._theme.modifier)
|
||||
self._cModifier.setFontWeight(self._bold)
|
||||
|
||||
self._cKeyword = QTextCharFormat(self._cText)
|
||||
self._cKeyword.setForeground(self._theme.keyword)
|
||||
|
||||
@@ -252,19 +240,9 @@ class ToQTextDocument(Tokenizer):
|
||||
newBlock(cursor, bFmt)
|
||||
cursor.insertText(nwUnicode.U_NBSP, self._cText)
|
||||
|
||||
elif tType in self.L_SUMMARY and self._doSynopsis:
|
||||
elif tType in self.L_NOTES:
|
||||
newBlock(cursor, bFmt)
|
||||
modifier = self._localLookup(
|
||||
"Short Description" if tType == BlockTyp.SHORT else "Synopsis"
|
||||
)
|
||||
cursor.insertText(f"{modifier}: ", self._cModifier)
|
||||
self._insertFragments(tText, tFormat, cursor, self._cNote)
|
||||
|
||||
elif tType == BlockTyp.COMMENT and self._doComments:
|
||||
newBlock(cursor, bFmt)
|
||||
modifier = self._localLookup("Comment")
|
||||
cursor.insertText(f"{modifier}: ", self._cCommentMod)
|
||||
self._insertFragments(tText, tFormat, cursor, self._cComment)
|
||||
self._insertFragments(tText, tFormat, cursor, self._cText)
|
||||
|
||||
elif tType == BlockTyp.KEYWORD and self._doKeywords:
|
||||
newBlock(cursor, bFmt)
|
||||
@@ -359,6 +337,15 @@ class ToQTextDocument(Tokenizer):
|
||||
cFmt.setVerticalAlignment(QtVAlignSub)
|
||||
elif fmt == TextFmt.SUB_E:
|
||||
cFmt.setVerticalAlignment(QtVAlignNormal)
|
||||
elif fmt == TextFmt.SUB_B:
|
||||
cFmt.setVerticalAlignment(QtVAlignSub)
|
||||
elif fmt == TextFmt.SUB_E:
|
||||
cFmt.setVerticalAlignment(QtVAlignNormal)
|
||||
elif fmt == TextFmt.COL_B:
|
||||
if color := self._classes.get(data):
|
||||
cFmt.setForeground(color)
|
||||
elif fmt == TextFmt.COL_E:
|
||||
cFmt.setForeground(self._theme.text)
|
||||
elif fmt == TextFmt.DL_B:
|
||||
cFmt.setForeground(self._theme.dialog)
|
||||
elif fmt == TextFmt.DL_E:
|
||||
|
||||
Reference in New Issue
Block a user