Convert format codes to enums

This commit is contained in:
Veronica Berglyd Olsen
2024-10-21 23:37:27 +02:00
parent f91006631d
commit 38ca447c8a
12 changed files with 817 additions and 789 deletions
+47 -47
View File
@@ -39,7 +39,7 @@ from novelwriter import __version__
from novelwriter.common import firstFloat, xmlSubElem
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles
from novelwriter.core.project import NWProject
from novelwriter.formats.tokenizer import T_Formats, Tokenizer
from novelwriter.formats.tokenizer import BlockFmt, BlockTyp, T_Formats, TextFmt, Tokenizer
logger = logging.getLogger(__name__)
@@ -227,75 +227,75 @@ class ToDocX(Tokenizer):
# Styles
if tStyle is not None:
if tStyle & self.A_LEFT:
if tStyle & BlockFmt.LEFT:
par.setAlignment("left")
elif tStyle & self.A_RIGHT:
elif tStyle & BlockFmt.RIGHT:
par.setAlignment("right")
elif tStyle & self.A_CENTRE:
elif tStyle & BlockFmt.CENTRE:
par.setAlignment("center")
elif tStyle & self.A_JUSTIFY:
elif tStyle & BlockFmt.JUSTIFY:
par.setAlignment("both")
if tStyle & self.A_PBB:
if tStyle & BlockFmt.PBB:
par.setPageBreakBefore(True)
if tStyle & self.A_PBA:
if tStyle & BlockFmt.PBA:
par.setPageBreakAfter(True)
if tStyle & self.A_Z_BTMMRG:
if tStyle & BlockFmt.Z_BTMMRG:
par.setMarginBottom(0.0)
if tStyle & self.A_Z_TOPMRG:
if tStyle & BlockFmt.Z_TOPMRG:
par.setMarginTop(0.0)
if tStyle & self.A_IND_T:
if tStyle & BlockFmt.IND_T:
par.setIndentFirst(True)
if tStyle & self.A_IND_L:
if tStyle & BlockFmt.IND_L:
par.setMarginLeft(bIndent)
if tStyle & self.A_IND_R:
if tStyle & BlockFmt.IND_R:
par.setMarginRight(bIndent)
# Process Text Types
if tType == self.T_TEXT:
if tType == BlockTyp.TEXT:
self._processFragments(par, S_NORM, tText, tFormat)
elif tType == self.T_TITLE:
elif tType == BlockTyp.TITLE:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._processFragments(par, S_TITLE, tHead, tFormat)
elif tType == self.T_HEAD1:
elif tType == BlockTyp.HEAD1:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._processFragments(par, S_HEAD1, tHead, tFormat)
elif tType == self.T_HEAD2:
elif tType == BlockTyp.HEAD2:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._processFragments(par, S_HEAD2, tHead, tFormat)
elif tType == self.T_HEAD3:
elif tType == BlockTyp.HEAD3:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._processFragments(par, S_HEAD3, tHead, tFormat)
elif tType == self.T_HEAD4:
elif tType == BlockTyp.HEAD4:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._processFragments(par, S_HEAD4, tHead, tFormat)
elif tType == self.T_SEP:
elif tType == BlockTyp.SEP:
self._processFragments(par, S_SEP, tText)
elif tType == self.T_SKIP:
elif tType == BlockTyp.SKIP:
self._processFragments(par, S_NORM, "")
elif tType == self.T_SYNOPSIS and self._doSynopsis:
elif tType == BlockTyp.SYNOPSIS and self._doSynopsis:
tTemp, tFmt = self._formatSynopsis(tText, tFormat, True)
self._processFragments(par, S_META, tTemp, tFmt)
elif tType == self.T_SHORT and self._doSynopsis:
elif tType == BlockTyp.SHORT and self._doSynopsis:
tTemp, tFmt = self._formatSynopsis(tText, tFormat, False)
self._processFragments(par, S_META, tTemp, tFmt)
elif tType == self.T_COMMENT and self._doComments:
elif tType == BlockTyp.COMMENT and self._doComments:
tTemp, tFmt = self._formatComments(tText, tFormat)
self._processFragments(par, S_META, tTemp, tFmt)
elif tType == self.T_KEYWORD and self._doKeywords:
elif tType == BlockTyp.KEYWORD and self._doKeywords:
tTemp, tFmt = self._formatKeywords(tText)
self._processFragments(par, S_META, tTemp, tFmt)
@@ -378,7 +378,7 @@ class ToDocX(Tokenizer):
name = self._localLookup("Synopsis" if synopsis else "Short Description")
shift = len(name) + 2
rTxt = f"{name}: {text}"
rFmt: T_Formats = [(0, self.FMT_B_B, ""), (len(name) + 1, self.FMT_B_E, "")]
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
@@ -387,7 +387,7 @@ class ToDocX(Tokenizer):
name = self._localLookup("Comment")
shift = len(name) + 2
rTxt = f"{name}: {text}"
rFmt: T_Formats = [(0, self.FMT_B_B, ""), (len(name) + 1, self.FMT_B_E, "")]
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
@@ -398,7 +398,7 @@ class ToDocX(Tokenizer):
return "", []
rTxt = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: "
rFmt: T_Formats = [(0, self.FMT_B_B, ""), (len(rTxt) - 1, self.FMT_B_E, "")]
rFmt: T_Formats = [(0, TextFmt.B_B, ""), (len(rTxt) - 1, TextFmt.B_E, "")]
if len(bits) > 1:
if bits[0] == nwKeyWords.TAG_KEY:
rTxt += bits[1]
@@ -424,45 +424,45 @@ class ToDocX(Tokenizer):
if temp := text[fStart:fPos]:
par.addContent(self._textRunToXml(temp, xFmt))
if fFmt == self.FMT_B_B:
if fFmt == TextFmt.B_B:
xFmt |= X_BLD
elif fFmt == self.FMT_B_E:
elif fFmt == TextFmt.B_E:
xFmt &= M_BLD
elif fFmt == self.FMT_I_B:
elif fFmt == TextFmt.I_B:
xFmt |= X_ITA
elif fFmt == self.FMT_I_E:
elif fFmt == TextFmt.I_E:
xFmt &= M_ITA
elif fFmt == self.FMT_D_B:
elif fFmt == TextFmt.D_B:
xFmt |= X_DEL
elif fFmt == self.FMT_D_E:
elif fFmt == TextFmt.D_E:
xFmt &= M_DEL
elif fFmt == self.FMT_U_B:
elif fFmt == TextFmt.U_B:
xFmt |= X_UND
elif fFmt == self.FMT_U_E:
elif fFmt == TextFmt.U_E:
xFmt &= M_UND
elif fFmt == self.FMT_M_B:
elif fFmt == TextFmt.M_B:
xFmt |= X_MRK
elif fFmt == self.FMT_M_E:
elif fFmt == TextFmt.M_E:
xFmt &= M_MRK
elif fFmt == self.FMT_SUP_B:
elif fFmt == TextFmt.SUP_B:
xFmt |= X_SUP
elif fFmt == self.FMT_SUP_E:
elif fFmt == TextFmt.SUP_E:
xFmt &= M_SUP
elif fFmt == self.FMT_SUB_B:
elif fFmt == TextFmt.SUB_B:
xFmt |= X_SUB
elif fFmt == self.FMT_SUB_E:
elif fFmt == TextFmt.SUB_E:
xFmt &= M_SUB
elif fFmt == self.FMT_DL_B:
elif fFmt == TextFmt.DL_B:
xFmt |= X_DLG
elif fFmt == self.FMT_DL_E:
elif fFmt == TextFmt.DL_E:
xFmt &= M_DLG
elif fFmt == self.FMT_ADL_B:
elif fFmt == TextFmt.ADL_B:
xFmt |= X_DLA
elif fFmt == self.FMT_ADL_E:
elif fFmt == TextFmt.ADL_E:
xFmt &= M_DLA
elif fFmt == self.FMT_FNOTE:
elif fFmt == TextFmt.FNOTE:
xNode = self._generateFootnote(fData)
elif fFmt == self.FMT_STRIP:
elif fFmt == TextFmt.STRIP:
pass
# Move pos for next pass
+45 -43
View File
@@ -32,35 +32,37 @@ from time import time
from novelwriter.common import formatTimeStamp
from novelwriter.constants import nwHeadFmt, nwHtmlUnicode, nwKeyWords, nwLabels
from novelwriter.core.project import NWProject
from novelwriter.formats.tokenizer import T_Formats, Tokenizer, stripEscape
from novelwriter.formats.tokenizer import (
BlockFmt, BlockTyp, T_Formats, TextFmt, Tokenizer, stripEscape
)
from novelwriter.types import FONT_STYLE, FONT_WEIGHTS
logger = logging.getLogger(__name__)
# Each opener tag, with the id of its corresponding closer and tag format
HTML_OPENER: dict[int, tuple[int, str]] = {
Tokenizer.FMT_B_B: (Tokenizer.FMT_B_E, "<strong>"),
Tokenizer.FMT_I_B: (Tokenizer.FMT_I_E, "<em>"),
Tokenizer.FMT_D_B: (Tokenizer.FMT_D_E, "<del>"),
Tokenizer.FMT_U_B: (Tokenizer.FMT_U_E, "<span style='text-decoration: underline;'>"),
Tokenizer.FMT_M_B: (Tokenizer.FMT_M_E, "<mark>"),
Tokenizer.FMT_SUP_B: (Tokenizer.FMT_SUP_E, "<sup>"),
Tokenizer.FMT_SUB_B: (Tokenizer.FMT_SUB_E, "<sub>"),
Tokenizer.FMT_DL_B: (Tokenizer.FMT_DL_E, "<span class='dialog'>"),
Tokenizer.FMT_ADL_B: (Tokenizer.FMT_ADL_E, "<span class='altdialog'>"),
TextFmt.B_B: (TextFmt.B_E, "<strong>"),
TextFmt.I_B: (TextFmt.I_E, "<em>"),
TextFmt.D_B: (TextFmt.D_E, "<del>"),
TextFmt.U_B: (TextFmt.U_E, "<span style='text-decoration: underline;'>"),
TextFmt.M_B: (TextFmt.M_E, "<mark>"),
TextFmt.SUP_B: (TextFmt.SUP_E, "<sup>"),
TextFmt.SUB_B: (TextFmt.SUB_E, "<sub>"),
TextFmt.DL_B: (TextFmt.DL_E, "<span class='dialog'>"),
TextFmt.ADL_B: (TextFmt.ADL_E, "<span class='altdialog'>"),
}
# Each closer tag, with the id of its corresponding opener and tag format
HTML_CLOSER: dict[int, tuple[int, str]] = {
Tokenizer.FMT_B_E: (Tokenizer.FMT_B_B, "</strong>"),
Tokenizer.FMT_I_E: (Tokenizer.FMT_I_B, "</em>"),
Tokenizer.FMT_D_E: (Tokenizer.FMT_D_B, "</del>"),
Tokenizer.FMT_U_E: (Tokenizer.FMT_U_B, "</span>"),
Tokenizer.FMT_M_E: (Tokenizer.FMT_M_B, "</mark>"),
Tokenizer.FMT_SUP_E: (Tokenizer.FMT_SUP_B, "</sup>"),
Tokenizer.FMT_SUB_E: (Tokenizer.FMT_SUB_B, "</sub>"),
Tokenizer.FMT_DL_E: (Tokenizer.FMT_DL_B, "</span>"),
Tokenizer.FMT_ADL_E: (Tokenizer.FMT_ADL_B, "</span>"),
TextFmt.B_E: (TextFmt.B_B, "</strong>"),
TextFmt.I_E: (TextFmt.I_B, "</em>"),
TextFmt.D_E: (TextFmt.D_B, "</del>"),
TextFmt.U_E: (TextFmt.U_B, "</span>"),
TextFmt.M_E: (TextFmt.M_B, "</mark>"),
TextFmt.SUP_E: (TextFmt.SUP_B, "</sup>"),
TextFmt.SUB_E: (TextFmt.SUB_B, "</sub>"),
TextFmt.DL_E: (TextFmt.DL_B, "</span>"),
TextFmt.ADL_E: (TextFmt.ADL_B, "</span>"),
}
# Empty HTML tag record
@@ -183,30 +185,30 @@ class ToHtml(Tokenizer):
# Styles
aStyle = []
if tStyle is not None and self._cssStyles:
if tStyle & self.A_LEFT:
if tStyle & BlockFmt.LEFT:
aStyle.append("text-align: left;")
elif tStyle & self.A_RIGHT:
elif tStyle & BlockFmt.RIGHT:
aStyle.append("text-align: right;")
elif tStyle & self.A_CENTRE:
elif tStyle & BlockFmt.CENTRE:
aStyle.append("text-align: center;")
elif tStyle & self.A_JUSTIFY:
elif tStyle & BlockFmt.JUSTIFY:
aStyle.append("text-align: justify;")
if tStyle & self.A_PBB:
if tStyle & BlockFmt.PBB:
aStyle.append("page-break-before: always;")
if tStyle & self.A_PBA:
if tStyle & BlockFmt.PBA:
aStyle.append("page-break-after: always;")
if tStyle & self.A_Z_BTMMRG:
if tStyle & BlockFmt.Z_BTMMRG:
aStyle.append("margin-bottom: 0;")
if tStyle & self.A_Z_TOPMRG:
if tStyle & BlockFmt.Z_TOPMRG:
aStyle.append("margin-top: 0;")
if tStyle & self.A_IND_L:
if tStyle & BlockFmt.IND_L:
aStyle.append(f"margin-left: {self._blockIndent:.2f}em;")
if tStyle & self.A_IND_R:
if tStyle & BlockFmt.IND_R:
aStyle.append(f"margin-right: {self._blockIndent:.2f}em;")
if tStyle & self.A_IND_T:
if tStyle & BlockFmt.IND_T:
aStyle.append(f"text-indent: {self._firstWidth:.2f}em;")
if aStyle:
@@ -221,45 +223,45 @@ class ToHtml(Tokenizer):
aNm = ""
# Process Text Type
if tType == self.T_TEXT:
if tType == BlockTyp.TEXT:
lines.append(f"<p{hStyle}>{self._formatText(tText, tFormat)}</p>\n")
elif tType == self.T_TITLE:
elif tType == BlockTyp.TITLE:
tHead = tText.replace(nwHeadFmt.BR, "<br>")
lines.append(f"<h1 class='title'{hStyle}>{aNm}{tHead}</h1>\n")
elif tType == self.T_HEAD1:
elif tType == BlockTyp.HEAD1:
tHead = tText.replace(nwHeadFmt.BR, "<br>")
lines.append(f"<{h1}{h1Cl}{hStyle}>{aNm}{tHead}</{h1}>\n")
elif tType == self.T_HEAD2:
elif tType == BlockTyp.HEAD2:
tHead = tText.replace(nwHeadFmt.BR, "<br>")
lines.append(f"<{h2}{hStyle}>{aNm}{tHead}</{h2}>\n")
elif tType == self.T_HEAD3:
elif tType == BlockTyp.HEAD3:
tHead = tText.replace(nwHeadFmt.BR, "<br>")
lines.append(f"<{h3}{hStyle}>{aNm}{tHead}</{h3}>\n")
elif tType == self.T_HEAD4:
elif tType == BlockTyp.HEAD4:
tHead = tText.replace(nwHeadFmt.BR, "<br>")
lines.append(f"<{h4}{hStyle}>{aNm}{tHead}</{h4}>\n")
elif tType == self.T_SEP:
elif tType == BlockTyp.SEP:
lines.append(f"<p class='sep'{hStyle}>{tText}</p>\n")
elif tType == self.T_SKIP:
elif tType == BlockTyp.SKIP:
lines.append(f"<p class='skip'{hStyle}>&nbsp;</p>\n")
elif tType == self.T_SYNOPSIS and self._doSynopsis:
elif tType == BlockTyp.SYNOPSIS and self._doSynopsis:
lines.append(self._formatSynopsis(self._formatText(tText, tFormat), True))
elif tType == self.T_SHORT and self._doSynopsis:
elif tType == BlockTyp.SHORT and self._doSynopsis:
lines.append(self._formatSynopsis(self._formatText(tText, tFormat), False))
elif tType == self.T_COMMENT and self._doComments:
elif tType == BlockTyp.COMMENT and self._doComments:
lines.append(self._formatComments(self._formatText(tText, tFormat)))
elif tType == self.T_KEYWORD and self._doKeywords:
elif tType == BlockTyp.KEYWORD and self._doKeywords:
tag, text = self._formatKeywords(tText)
kClass = f" class='meta meta-{tag}'" if tag else ""
tTemp = f"<p{kClass}{hStyle}>{text}</p>\n"
@@ -469,7 +471,7 @@ class ToHtml(Tokenizer):
if state.get(m[0], False):
tags.append((pos, m[1]))
state[m[0]] = False
elif fmt == self.FMT_FNOTE:
elif fmt == TextFmt.FNOTE:
if data in self._footnotes:
index = len(self._usedNotes) + 1
self._usedNotes[data] = index
+170 -153
View File
@@ -29,6 +29,7 @@ import logging
import re
from abc import ABC, abstractmethod
from enum import Flag, IntEnum
from functools import partial
from pathlib import Path
from time import time
@@ -51,10 +52,6 @@ logger = logging.getLogger(__name__)
ESCAPES = {r"\*": "*", r"\~": "~", r"\_": "_", r"\[": "[", r"\]": "]", r"\ ": ""}
RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL)
T_Formats = list[tuple[int, int, str]]
T_Comment = tuple[str, T_Formats]
T_Token = tuple[int, int, str, T_Formats, int]
def stripEscape(text: str) -> str:
"""Strip escaped Markdown characters from paragraph text."""
@@ -63,6 +60,68 @@ def stripEscape(text: str) -> str:
return text
class TextFmt(IntEnum):
B_B = 1 # Begin bold
B_E = 2 # End bold
I_B = 3 # Begin italics
I_E = 4 # End italics
D_B = 5 # Begin strikeout
D_E = 6 # End strikeout
U_B = 7 # Begin underline
U_E = 8 # End underline
M_B = 9 # Begin mark
M_E = 10 # End mark
SUP_B = 11 # Begin superscript
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
class BlockTyp(IntEnum):
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
class BlockFmt(Flag):
NONE = 0x0000 # No special style
LEFT = 0x0001 # Left aligned
RIGHT = 0x0002 # Right aligned
CENTRE = 0x0004 # Centred
JUSTIFY = 0x0008 # Justified
PBB = 0x0010 # Page break before
PBA = 0x0020 # Page break after
Z_TOPMRG = 0x0040 # Zero top margin
Z_BTMMRG = 0x0080 # Zero bottom margin
IND_L = 0x0100 # Left indentation
IND_R = 0x0200 # Right indentation
IND_T = 0x0400 # Text indentation
T_Formats = list[tuple[int, TextFmt, str]]
T_Comment = tuple[str, T_Formats]
T_Token = tuple[BlockTyp, int, str, T_Formats, BlockFmt]
class Tokenizer(ABC):
"""Core: Text Tokenizer Abstract Base Class
@@ -72,64 +131,18 @@ class Tokenizer(ABC):
subclasses.
"""
# In-Text Format
FMT_B_B = 1 # Begin bold
FMT_B_E = 2 # End bold
FMT_I_B = 3 # Begin italics
FMT_I_E = 4 # End italics
FMT_D_B = 5 # Begin strikeout
FMT_D_E = 6 # End strikeout
FMT_U_B = 7 # Begin underline
FMT_U_E = 8 # End underline
FMT_M_B = 9 # Begin mark
FMT_M_E = 10 # End mark
FMT_SUP_B = 11 # Begin superscript
FMT_SUP_E = 12 # End superscript
FMT_SUB_B = 13 # Begin subscript
FMT_SUB_E = 14 # End subscript
FMT_DL_B = 15 # Begin dialogue
FMT_DL_E = 16 # End dialogue
FMT_ADL_B = 17 # Begin alt dialogue
FMT_ADL_E = 18 # End alt dialogue
FMT_FNOTE = 19 # Footnote marker
FMT_STRIP = 20 # Strip the format code
# Block Type
T_EMPTY = 1 # Empty line (new paragraph)
T_SYNOPSIS = 2 # Synopsis comment
T_SHORT = 3 # Short description comment
T_COMMENT = 4 # Comment line
T_KEYWORD = 5 # Command line
T_TITLE = 6 # Title
T_HEAD1 = 7 # Heading 1
T_HEAD2 = 8 # Heading 2
T_HEAD3 = 9 # Heading 3
T_HEAD4 = 10 # Heading 4
T_TEXT = 11 # Text line
T_SEP = 12 # Scene separator
T_SKIP = 13 # Paragraph break
# Block Style
A_NONE = 0x0000 # No special style
A_LEFT = 0x0001 # Left aligned
A_RIGHT = 0x0002 # Right aligned
A_CENTRE = 0x0004 # Centred
A_JUSTIFY = 0x0008 # Justified
A_PBB = 0x0010 # Page break before
A_PBA = 0x0020 # Page break after
A_Z_TOPMRG = 0x0040 # Zero top margin
A_Z_BTMMRG = 0x0080 # Zero bottom margin
A_IND_L = 0x0100 # Left indentation
A_IND_R = 0x0200 # Right indentation
A_IND_T = 0x0400 # Text indentation
# Masks
M_ALIGNED = A_LEFT | A_RIGHT | A_CENTRE | A_JUSTIFY
M_ALIGNED = BlockFmt.LEFT | BlockFmt.RIGHT | BlockFmt.CENTRE | BlockFmt.JUSTIFY
# Lookups
L_HEADINGS = [T_TITLE, T_HEAD1, T_HEAD2, T_HEAD3, T_HEAD4]
L_SKIP_INDENT = [T_TITLE, T_HEAD1, T_HEAD2, T_HEAD2, T_HEAD3, T_HEAD4, T_SEP, T_SKIP]
L_SUMMARY = [T_SYNOPSIS, T_SHORT]
L_HEADINGS = [
BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4,
]
L_SKIP_INDENT = [
BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD2, BlockTyp.HEAD3,
BlockTyp.HEAD4, BlockTyp.SEP, BlockTyp.SKIP,
]
L_SUMMARY = [BlockTyp.SYNOPSIS, BlockTyp.SHORT]
def __init__(self, project: NWProject) -> None:
@@ -197,10 +210,10 @@ class Tokenizer(ABC):
self._linkHeadings = False # Add an anchor before headings
self._titleStyle = self.A_CENTRE | self.A_PBB
self._partStyle = self.A_CENTRE | self.A_PBB
self._chapterStyle = self.A_PBB
self._sceneStyle = self.A_NONE
self._titleStyle = BlockFmt.CENTRE | BlockFmt.PBB
self._partStyle = BlockFmt.CENTRE | BlockFmt.PBB
self._chapterStyle = BlockFmt.PBB
self._sceneStyle = BlockFmt.NONE
# Instance Variables
self._hFormatter = HeadingFormatter(self._project)
@@ -220,24 +233,24 @@ class Tokenizer(ABC):
# Format RegEx
self._rxMarkdown = [
(REGEX_PATTERNS.markdownItalic, [0, self.FMT_I_B, 0, self.FMT_I_E]),
(REGEX_PATTERNS.markdownBold, [0, self.FMT_B_B, 0, self.FMT_B_E]),
(REGEX_PATTERNS.markdownStrike, [0, self.FMT_D_B, 0, self.FMT_D_E]),
(REGEX_PATTERNS.markdownItalic, [0, TextFmt.I_B, 0, TextFmt.I_E]),
(REGEX_PATTERNS.markdownBold, [0, TextFmt.B_B, 0, TextFmt.B_E]),
(REGEX_PATTERNS.markdownStrike, [0, TextFmt.D_B, 0, TextFmt.D_E]),
]
self._rxShortCodes = REGEX_PATTERNS.shortcodePlain
self._rxShortCodeVals = REGEX_PATTERNS.shortcodeValue
self._shortCodeFmt = {
nwShortcode.ITALIC_O: self.FMT_I_B, nwShortcode.ITALIC_C: self.FMT_I_E,
nwShortcode.BOLD_O: self.FMT_B_B, nwShortcode.BOLD_C: self.FMT_B_E,
nwShortcode.STRIKE_O: self.FMT_D_B, nwShortcode.STRIKE_C: self.FMT_D_E,
nwShortcode.ULINE_O: self.FMT_U_B, nwShortcode.ULINE_C: self.FMT_U_E,
nwShortcode.MARK_O: self.FMT_M_B, nwShortcode.MARK_C: self.FMT_M_E,
nwShortcode.SUP_O: self.FMT_SUP_B, nwShortcode.SUP_C: self.FMT_SUP_E,
nwShortcode.SUB_O: self.FMT_SUB_B, nwShortcode.SUB_C: self.FMT_SUB_E,
nwShortcode.ITALIC_O: TextFmt.I_B, nwShortcode.ITALIC_C: TextFmt.I_E,
nwShortcode.BOLD_O: TextFmt.B_B, nwShortcode.BOLD_C: TextFmt.B_E,
nwShortcode.STRIKE_O: TextFmt.D_B, nwShortcode.STRIKE_C: TextFmt.D_E,
nwShortcode.ULINE_O: TextFmt.U_B, nwShortcode.ULINE_C: TextFmt.U_E,
nwShortcode.MARK_O: TextFmt.M_B, nwShortcode.MARK_C: TextFmt.M_E,
nwShortcode.SUP_O: TextFmt.SUP_B, nwShortcode.SUP_C: TextFmt.SUP_E,
nwShortcode.SUB_O: TextFmt.SUB_B, nwShortcode.SUB_C: TextFmt.SUB_E,
}
self._shortCodeVals = {
nwShortcode.FOOTNOTE_B: self.FMT_FNOTE,
nwShortcode.FOOTNOTE_B: TextFmt.FNOTE,
}
self._rxDialogue: list[tuple[re.Pattern, int, int]] = []
@@ -316,28 +329,32 @@ class Tokenizer(ABC):
def setTitleStyle(self, center: bool, pageBreak: bool) -> None:
"""Set the title heading style."""
self._titleStyle = (
(self.A_CENTRE if center else self.A_NONE) | (self.A_PBB if pageBreak else self.A_NONE)
(BlockFmt.CENTRE if center else BlockFmt.NONE)
| (BlockFmt.PBB if pageBreak else BlockFmt.NONE)
)
return
def setPartitionStyle(self, center: bool, pageBreak: bool) -> None:
"""Set the partition heading style."""
self._partStyle = (
(self.A_CENTRE if center else self.A_NONE) | (self.A_PBB if pageBreak else self.A_NONE)
(BlockFmt.CENTRE if center else BlockFmt.NONE)
| (BlockFmt.PBB if pageBreak else BlockFmt.NONE)
)
return
def setChapterStyle(self, center: bool, pageBreak: bool) -> None:
"""Set the chapter heading style."""
self._chapterStyle = (
(self.A_CENTRE if center else self.A_NONE) | (self.A_PBB if pageBreak else self.A_NONE)
(BlockFmt.CENTRE if center else BlockFmt.NONE)
| (BlockFmt.PBB if pageBreak else BlockFmt.NONE)
)
return
def setSceneStyle(self, center: bool, pageBreak: bool) -> None:
"""Set the scene heading style."""
self._sceneStyle = (
(self.A_CENTRE if center else self.A_NONE) | (self.A_PBB if pageBreak else self.A_NONE)
(BlockFmt.CENTRE if center else BlockFmt.NONE)
| (BlockFmt.PBB if pageBreak else BlockFmt.NONE)
)
return
@@ -383,19 +400,19 @@ class Tokenizer(ABC):
if state:
if CONFIG.dialogStyle > 0:
self._rxDialogue.append((
REGEX_PATTERNS.dialogStyle, self.FMT_DL_B, self.FMT_DL_E
REGEX_PATTERNS.dialogStyle, TextFmt.DL_B, TextFmt.DL_E
))
if CONFIG.dialogLine:
self._rxDialogue.append((
REGEX_PATTERNS.dialogLine, self.FMT_DL_B, self.FMT_DL_E
REGEX_PATTERNS.dialogLine, TextFmt.DL_B, TextFmt.DL_E
))
if CONFIG.narratorBreak:
self._rxDialogue.append((
REGEX_PATTERNS.narratorBreak, self.FMT_DL_E, self.FMT_DL_B
REGEX_PATTERNS.narratorBreak, TextFmt.DL_E, TextFmt.DL_B
))
if CONFIG.altDialogOpen and CONFIG.altDialogClose:
self._rxDialogue.append((
REGEX_PATTERNS.altDialogStyle, self.FMT_ADL_B, self.FMT_ADL_E
REGEX_PATTERNS.altDialogStyle, TextFmt.ADL_B, TextFmt.ADL_E
))
return
@@ -494,16 +511,16 @@ class Tokenizer(ABC):
if (tItem := self._project.tree[tHandle]) and tItem.isRootType():
self._handle = tHandle
if self._isFirst:
textAlign = self.A_CENTRE
textAlign = BlockFmt.CENTRE
self._isFirst = False
else:
textAlign = self.A_PBB | self.A_CENTRE
textAlign = BlockFmt.PBB | BlockFmt.CENTRE
trNotes = self._localLookup("Notes")
title = f"{trNotes}: {tItem.itemName}"
self._tokens = []
self._tokens.append((
self.T_TITLE, 1, title, [], textAlign
BlockTyp.TITLE, 1, title, [], textAlign
))
if self._keepRaw:
self._markdown.append(f"#! {title}\n\n")
@@ -548,11 +565,11 @@ class Tokenizer(ABC):
The format of the token list is an entry with a five-tuple for
each line in the file. The tuple is as follows:
1: The type of the block, self.T_*
1: The type of the block, BlockType.*
2: The heading number under which the text is placed
3: The text content of the block, without leading tags
4: The internal formatting map of the text, self.FMT_*
5: The style of the block, self.A_*
4: The internal formatting map of the text, TxtFmt.*
5: The style of the block, BlockFmt.*
"""
if self._isNovel:
self._hFormatter.setHandle(self._handle)
@@ -568,7 +585,7 @@ class Tokenizer(ABC):
# Check for blank lines
if len(sLine) == 0:
tokens.append((
self.T_EMPTY, nHead, "", [], self.A_NONE
BlockTyp.EMPTY, nHead, "", [], BlockFmt.NONE
))
if self._keepRaw:
tmpMarkdown.append("\n")
@@ -576,10 +593,10 @@ class Tokenizer(ABC):
continue
if breakNext:
sAlign = self.A_PBB
sAlign = BlockFmt.PBB
breakNext = False
else:
sAlign = self.A_NONE
sAlign = BlockFmt.NONE
# Check Line Format
# =================
@@ -597,7 +614,7 @@ class Tokenizer(ABC):
elif sLine == "[vspace]":
tokens.append(
(self.T_SKIP, nHead, "", [], sAlign)
(BlockTyp.SKIP, nHead, "", [], sAlign)
)
continue
@@ -605,11 +622,11 @@ class Tokenizer(ABC):
nSkip = checkInt(sLine[8:-1], 0)
if nSkip >= 1:
tokens.append(
(self.T_SKIP, nHead, "", [], sAlign)
(BlockTyp.SKIP, nHead, "", [], sAlign)
)
if nSkip > 1:
tokens += (nSkip - 1) * [
(self.T_SKIP, nHead, "", [], self.A_NONE)
(BlockTyp.SKIP, nHead, "", [], BlockFmt.NONE)
]
continue
@@ -623,32 +640,32 @@ class Tokenizer(ABC):
continue
if self._doJustify and not sAlign & self.M_ALIGNED:
sAlign |= self.A_JUSTIFY
sAlign |= BlockFmt.JUSTIFY
cStyle, cKey, cText, _, _ = processComment(aLine)
if cStyle == nwComment.SYNOPSIS:
tLine, tFmt = self._extractFormats(cText)
tokens.append((
self.T_SYNOPSIS, nHead, tLine, tFmt, sAlign
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)
tokens.append((
self.T_SHORT, nHead, tLine, tFmt, sAlign
BlockTyp.SHORT, nHead, tLine, tFmt, sAlign
))
if self._doSynopsis and self._keepRaw:
tmpMarkdown.append(f"{aLine}\n")
elif cStyle == nwComment.FOOTNOTE:
tLine, tFmt = self._extractFormats(cText, skip=self.FMT_FNOTE)
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)
tokens.append((
self.T_COMMENT, nHead, tLine, tFmt, sAlign
BlockTyp.COMMENT, nHead, tLine, tFmt, sAlign
))
if self._doComments and self._keepRaw:
tmpMarkdown.append(f"{aLine}\n")
@@ -665,7 +682,7 @@ class Tokenizer(ABC):
and bits[0] not in self._skipKeywords
):
tokens.append((
self.T_KEYWORD, nHead, aLine[1:].strip(), [], sAlign
BlockTyp.KEYWORD, nHead, aLine[1:].strip(), [], sAlign
))
if self._doKeywords and self._keepRaw:
tmpMarkdown.append(f"{aLine}\n")
@@ -683,14 +700,14 @@ class Tokenizer(ABC):
nHead += 1
tText = aLine[2:].strip()
tType = self.T_HEAD1 if isPlain else self.T_TITLE
tStyle = self.A_NONE if isPlain else self._titleStyle
tType = BlockTyp.HEAD1 if isPlain else BlockTyp.TITLE
tStyle = BlockFmt.NONE if isPlain else self._titleStyle
sHide = self._hidePart if isPlain else False
if self._isNovel:
if sHide:
tText = ""
tType = self.T_EMPTY
tStyle = self.A_NONE
tType = BlockTyp.EMPTY
tStyle = BlockFmt.NONE
elif isPlain:
tText = self._hFormatter.apply(self._fmtPart, tText, nHead)
tStyle = self._partStyle
@@ -719,8 +736,8 @@ class Tokenizer(ABC):
nHead += 1
tText = aLine[3:].strip()
tType = self.T_HEAD2
tStyle = self.A_NONE
tType = BlockTyp.HEAD2
tStyle = BlockFmt.NONE
sHide = self._hideChapter if isPlain else self._hideUnNum
tFormat = self._fmtChapter if isPlain else self._fmtUnNum
if self._isNovel:
@@ -728,7 +745,7 @@ class Tokenizer(ABC):
self._hFormatter.incChapter()
if sHide:
tText = ""
tType = self.T_EMPTY
tType = BlockTyp.EMPTY
else:
tText = self._hFormatter.apply(tFormat, tText, nHead)
tStyle = self._chapterStyle
@@ -756,24 +773,24 @@ class Tokenizer(ABC):
nHead += 1
tText = aLine[4:].strip()
tType = self.T_HEAD3
tStyle = self.A_NONE
tType = BlockTyp.HEAD3
tStyle = BlockFmt.NONE
sHide = self._hideScene if isPlain else self._hideHScene
tFormat = self._fmtScene if isPlain else self._fmtHScene
if self._isNovel:
self._hFormatter.incScene()
if sHide:
tText = ""
tType = self.T_EMPTY
tType = BlockTyp.EMPTY
else:
tText = self._hFormatter.apply(tFormat, tText, nHead)
tStyle = self._sceneStyle
if tText == "": # Empty Format
tType = self.T_EMPTY if self._noSep else self.T_SKIP
tType = BlockTyp.EMPTY if self._noSep else BlockTyp.SKIP
elif tText == tFormat: # Static Format
tText = "" if self._noSep else tText
tType = self.T_EMPTY if self._noSep else self.T_SEP
tStyle = self.A_NONE if self._noSep else self.A_CENTRE
tType = BlockTyp.EMPTY if self._noSep else BlockTyp.SEP
tStyle = BlockFmt.NONE if self._noSep else BlockFmt.CENTRE
self._noSep = False
tokens.append((
@@ -792,19 +809,19 @@ class Tokenizer(ABC):
nHead += 1
tText = aLine[5:].strip()
tType = self.T_HEAD4
tStyle = self.A_NONE
tType = BlockTyp.HEAD4
tStyle = BlockFmt.NONE
if self._isNovel:
if self._hideSection:
tText = ""
tType = self.T_EMPTY
tType = BlockTyp.EMPTY
else:
tText = self._hFormatter.apply(self._fmtSection, tText, nHead)
if tText == "": # Empty Format
tType = self.T_SKIP
tType = BlockTyp.SKIP
elif tText == self._fmtSection: # Static Format
tType = self.T_SEP
tStyle = self.A_CENTRE
tType = BlockTyp.SEP
tStyle = BlockFmt.CENTRE
tokens.append((
tType, nHead, tText, [], tStyle
@@ -841,21 +858,21 @@ class Tokenizer(ABC):
aLine = aLine[:-1].rstrip(" ")
if alnLeft and alnRight:
sAlign |= self.A_CENTRE
sAlign |= BlockFmt.CENTRE
elif alnLeft:
sAlign |= self.A_LEFT
sAlign |= BlockFmt.LEFT
elif alnRight:
sAlign |= self.A_RIGHT
sAlign |= BlockFmt.RIGHT
if indLeft:
sAlign |= self.A_IND_L
sAlign |= BlockFmt.IND_L
if indRight:
sAlign |= self.A_IND_R
sAlign |= BlockFmt.IND_R
# Process formats
tLine, tFmt = self._extractFormats(aLine, hDialog=self._isNovel)
tokens.append((
self.T_TEXT, nHead, tLine, tFmt, sAlign
BlockTyp.TEXT, nHead, tLine, tFmt, sAlign
))
if self._keepRaw:
tmpMarkdown.append(f"{aLine}\n")
@@ -866,15 +883,15 @@ class Tokenizer(ABC):
# Make sure the token array doesn't start with a page break
# on the very first page, adding a blank first page.
if tokens[0][4] & self.A_PBB:
if tokens[0][4] & BlockFmt.PBB:
cToken = tokens[0]
tokens[0] = (
cToken[0], cToken[1], cToken[2], cToken[3], cToken[4] & ~self.A_PBB
cToken[0], cToken[1], cToken[2], cToken[3], cToken[4] & ~BlockFmt.PBB
)
# Always add an empty line at the end of the file
tokens.append((
self.T_EMPTY, nHead, "", [], self.A_NONE
BlockTyp.EMPTY, nHead, "", [], BlockFmt.NONE
))
if self._keepRaw:
tmpMarkdown.append("\n")
@@ -888,8 +905,8 @@ class Tokenizer(ABC):
# meta data lines for formats that has spacing.
self._tokens = []
pToken: T_Token = (self.T_EMPTY, 0, "", [], self.A_NONE)
nToken: T_Token = (self.T_EMPTY, 0, "", [], self.A_NONE)
pToken: T_Token = (BlockTyp.EMPTY, 0, "", [], BlockFmt.NONE)
nToken: T_Token = (BlockTyp.EMPTY, 0, "", [], BlockFmt.NONE)
lineSep = "\n" if self._keepBreaks else " "
pLines: list[T_Token] = []
@@ -908,26 +925,26 @@ class Tokenizer(ABC):
# specific type
self._noIndent = True
if cToken[0] == self.T_EMPTY:
if cToken[0] == BlockTyp.EMPTY:
# We don't need to keep the empty lines after this pass
pass
elif cToken[0] == self.T_KEYWORD:
elif cToken[0] == BlockTyp.KEYWORD:
# Adjust margins for lines in a list of keyword lines
aStyle = cToken[4]
if pToken[0] == self.T_KEYWORD:
aStyle |= self.A_Z_TOPMRG
if nToken[0] == self.T_KEYWORD:
aStyle |= self.A_Z_BTMMRG
if pToken[0] == BlockTyp.KEYWORD:
aStyle |= BlockFmt.Z_TOPMRG
if nToken[0] == BlockTyp.KEYWORD:
aStyle |= BlockFmt.Z_BTMMRG
self._tokens.append((
cToken[0], cToken[1], cToken[2], cToken[3], aStyle
))
elif cToken[0] == self.T_TEXT:
elif cToken[0] == BlockTyp.TEXT:
# Combine lines from the same paragraph
pLines.append(cToken)
if nToken[0] != self.T_TEXT:
if nToken[0] != BlockTyp.TEXT:
# Next token is not text, so we add the buffer to tokens
nLines = len(pLines)
cStyle = pLines[0][4]
@@ -935,16 +952,16 @@ class Tokenizer(ABC):
# If paragraph indentation is enabled, not temporarily
# turned off, and the block is not aligned, we add the
# text indentation flag
cStyle |= self.A_IND_T
cStyle |= BlockFmt.IND_T
if nLines == 1:
# The paragraph contains a single line, so we just save
# that directly to the token list. If justify is
# enabled, and there is no alignment, we apply it.
if self._doJustify and not cStyle & self.M_ALIGNED:
cStyle |= self.A_JUSTIFY
cStyle |= BlockFmt.JUSTIFY
self._tokens.append((
self.T_TEXT, pLines[0][1], pLines[0][2], pLines[0][3], cStyle
BlockTyp.TEXT, pLines[0][1], pLines[0][2], pLines[0][3], cStyle
))
elif nLines > 1:
# The paragraph contains multiple lines, so we need to
@@ -957,7 +974,7 @@ class Tokenizer(ABC):
tTxt += f"{aToken[2]}{lineSep}"
tFmt.extend((p+tLen, fmt, key) for p, fmt, key in aToken[3])
self._tokens.append((
self.T_TEXT, pLines[0][1], tTxt[:-1], tFmt, cStyle
BlockTyp.TEXT, pLines[0][1], tTxt[:-1], tFmt, cStyle
))
# Reset buffer and make sure text indent is on for next pass
@@ -974,13 +991,13 @@ class Tokenizer(ABC):
tHandle = self._handle or ""
isNovel = self._isNovel
for tType, nHead, tText, _, _ in self._tokens:
if tType == self.T_TITLE:
if tType == BlockTyp.TITLE:
prefix = "TT"
elif tType == self.T_HEAD1:
elif tType == BlockTyp.HEAD1:
prefix = "PT" if isNovel else "H1"
elif tType == self.T_HEAD2:
elif tType == BlockTyp.HEAD2:
prefix = "CH" if isNovel else "H2"
elif tType == self.T_HEAD3:
elif tType == BlockTyp.HEAD3:
prefix = "SC" if isNovel else "H3"
else:
continue
@@ -1017,7 +1034,7 @@ class Tokenizer(ABC):
nChars = len(tText)
nWChars = len("".join(tWords))
if tType == self.T_TEXT:
if tType == BlockTyp.TEXT:
tPWords = tText.split()
nPWords = len(tPWords)
nPChars = len(tText)
@@ -1040,33 +1057,33 @@ class Tokenizer(ABC):
titleChars += nChars
titleWordChars += nWChars
elif tType == self.T_SEP:
elif tType == BlockTyp.SEP:
allWords += nWords
allChars += nChars
allWordChars += nWChars
elif tType == self.T_SYNOPSIS and self._doSynopsis:
elif tType == BlockTyp.SYNOPSIS and self._doSynopsis:
text = "{0}: {1}".format(self._localLookup("Synopsis"), tText)
words = text.split()
allWords += len(words)
allChars += len(text)
allWordChars += len("".join(words))
elif tType == self.T_SHORT and self._doSynopsis:
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 == self.T_COMMENT and self._doComments:
elif tType == BlockTyp.COMMENT and self._doComments:
text = "{0}: {1}".format(self._localLookup("Comment"), tText)
words = text.split()
allWords += len(words)
allChars += len(text)
allWordChars += len("".join(words))
elif tType == self.T_KEYWORD and self._doKeywords:
elif tType == BlockTyp.KEYWORD and self._doKeywords:
valid, bits, _ = self._project.index.scanThis("@"+tText)
if valid and bits:
key = self._localLookup(nwLabels.KEY_NAME[bits[0]])
@@ -1155,7 +1172,7 @@ class Tokenizer(ABC):
kind = self._shortCodeVals.get(res.group(1).lower(), 0)
temp.append((
res.start(0), res.end(0),
self.FMT_STRIP if kind == skip else kind,
TextFmt.STRIP if kind == skip else kind,
f"{tHandle}:{res.group(2)}",
))
+47 -47
View File
@@ -29,47 +29,47 @@ from pathlib import Path
from novelwriter.constants import nwHeadFmt, nwLabels, nwUnicode
from novelwriter.core.project import NWProject
from novelwriter.formats.tokenizer import T_Formats, Tokenizer
from novelwriter.formats.tokenizer import BlockFmt, BlockTyp, T_Formats, TextFmt, Tokenizer
logger = logging.getLogger(__name__)
# Standard Markdown
STD_MD = {
Tokenizer.FMT_B_B: "**",
Tokenizer.FMT_B_E: "**",
Tokenizer.FMT_I_B: "_",
Tokenizer.FMT_I_E: "_",
Tokenizer.FMT_D_B: "",
Tokenizer.FMT_D_E: "",
Tokenizer.FMT_U_B: "",
Tokenizer.FMT_U_E: "",
Tokenizer.FMT_M_B: "",
Tokenizer.FMT_M_E: "",
Tokenizer.FMT_SUP_B: "",
Tokenizer.FMT_SUP_E: "",
Tokenizer.FMT_SUB_B: "",
Tokenizer.FMT_SUB_E: "",
Tokenizer.FMT_STRIP: "",
TextFmt.B_B: "**",
TextFmt.B_E: "**",
TextFmt.I_B: "_",
TextFmt.I_E: "_",
TextFmt.D_B: "",
TextFmt.D_E: "",
TextFmt.U_B: "",
TextFmt.U_E: "",
TextFmt.M_B: "",
TextFmt.M_E: "",
TextFmt.SUP_B: "",
TextFmt.SUP_E: "",
TextFmt.SUB_B: "",
TextFmt.SUB_E: "",
TextFmt.STRIP: "",
}
# Extended Markdown
EXT_MD = {
Tokenizer.FMT_B_B: "**",
Tokenizer.FMT_B_E: "**",
Tokenizer.FMT_I_B: "_",
Tokenizer.FMT_I_E: "_",
Tokenizer.FMT_D_B: "~~",
Tokenizer.FMT_D_E: "~~",
Tokenizer.FMT_U_B: "",
Tokenizer.FMT_U_E: "",
Tokenizer.FMT_M_B: "==",
Tokenizer.FMT_M_E: "==",
Tokenizer.FMT_SUP_B: "^",
Tokenizer.FMT_SUP_E: "^",
Tokenizer.FMT_SUB_B: "~",
Tokenizer.FMT_SUB_E: "~",
Tokenizer.FMT_STRIP: "",
TextFmt.B_B: "**",
TextFmt.B_E: "**",
TextFmt.I_B: "_",
TextFmt.I_E: "_",
TextFmt.D_B: "~~",
TextFmt.D_E: "~~",
TextFmt.U_B: "",
TextFmt.U_E: "",
TextFmt.M_B: "==",
TextFmt.M_E: "==",
TextFmt.SUP_B: "^",
TextFmt.SUP_E: "^",
TextFmt.SUB_B: "~",
TextFmt.SUB_E: "~",
TextFmt.STRIP: "",
}
@@ -119,49 +119,49 @@ class ToMarkdown(Tokenizer):
lines = []
for tType, _, tText, tFormat, tStyle in self._tokens:
if tType == self.T_TEXT:
if tType == BlockTyp.TEXT:
tTemp = self._formatText(tText, tFormat, mTags).replace("\n", " \n")
lines.append(f"{tTemp}\n\n")
elif tType == self.T_TITLE:
elif tType == BlockTyp.TITLE:
tHead = tText.replace(nwHeadFmt.BR, "\n")
lines.append(f"# {tHead}\n\n")
elif tType == self.T_HEAD1:
elif tType == BlockTyp.HEAD1:
tHead = tText.replace(nwHeadFmt.BR, "\n")
lines.append(f"# {tHead}\n\n")
elif tType == self.T_HEAD2:
elif tType == BlockTyp.HEAD2:
tHead = tText.replace(nwHeadFmt.BR, "\n")
lines.append(f"## {tHead}\n\n")
elif tType == self.T_HEAD3:
elif tType == BlockTyp.HEAD3:
tHead = tText.replace(nwHeadFmt.BR, "\n")
lines.append(f"### {tHead}\n\n")
elif tType == self.T_HEAD4:
elif tType == BlockTyp.HEAD4:
tHead = tText.replace(nwHeadFmt.BR, "\n")
lines.append(f"#### {tHead}\n\n")
elif tType == self.T_SEP:
elif tType == BlockTyp.SEP:
lines.append(f"{tText}\n\n")
elif tType == self.T_SKIP:
elif tType == BlockTyp.SKIP:
lines.append(f"{cSkip}\n\n")
elif tType == self.T_SYNOPSIS and self._doSynopsis:
elif tType == BlockTyp.SYNOPSIS and self._doSynopsis:
label = self._localLookup("Synopsis")
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
elif tType == self.T_SHORT and self._doSynopsis:
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 == self.T_COMMENT and self._doComments:
elif tType == BlockTyp.COMMENT and self._doComments:
label = self._localLookup("Comment")
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
elif tType == self.T_KEYWORD and self._doKeywords:
elif tType == BlockTyp.KEYWORD and self._doKeywords:
lines.append(self._formatKeywords(tText, tStyle))
self._result = "".join(lines)
@@ -207,12 +207,12 @@ class ToMarkdown(Tokenizer):
# Internal Functions
##
def _formatText(self, text: str, tFmt: T_Formats, tags: dict[int, str]) -> str:
def _formatText(self, text: str, tFmt: T_Formats, tags: dict[TextFmt, str]) -> str:
"""Apply formatting tags to text."""
temp = text
for pos, fmt, data in reversed(tFmt):
md = ""
if fmt == self.FMT_FNOTE:
if fmt == TextFmt.FNOTE:
if data in self._footnotes:
index = len(self._usedNotes) + 1
self._usedNotes[data] = index
@@ -224,7 +224,7 @@ class ToMarkdown(Tokenizer):
temp = f"{temp[:pos]}{md}{temp[pos:]}"
return temp
def _formatKeywords(self, text: str, style: int) -> str:
def _formatKeywords(self, text: str, style: BlockFmt) -> str:
"""Apply Markdown formatting to keywords."""
valid, bits, _ = self._project.index.scanThis("@"+text)
if not valid or not bits:
@@ -236,6 +236,6 @@ class ToMarkdown(Tokenizer):
if len(bits) > 1:
result += ", ".join(bits[1:])
result += " \n" if style & self.A_Z_BTMMRG else "\n\n"
result += " \n" if style & BlockFmt.Z_BTMMRG else "\n\n"
return result
+49 -47
View File
@@ -41,7 +41,9 @@ from novelwriter import __version__
from novelwriter.common import xmlIndent, xmlSubElem
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles
from novelwriter.core.project import NWProject
from novelwriter.formats.tokenizer import T_Formats, Tokenizer, stripEscape
from novelwriter.formats.tokenizer import (
BlockFmt, BlockTyp, T_Formats, TextFmt, Tokenizer, stripEscape
)
from novelwriter.types import FONT_STYLE, FONT_WEIGHTS
logger = logging.getLogger(__name__)
@@ -429,79 +431,79 @@ class ToOdt(Tokenizer):
# Styles
oStyle = ODTParagraphStyle("New")
if tStyle is not None:
if tStyle & self.A_LEFT:
if tStyle & BlockFmt.LEFT:
oStyle.setTextAlign("left")
elif tStyle & self.A_RIGHT:
elif tStyle & BlockFmt.RIGHT:
oStyle.setTextAlign("right")
elif tStyle & self.A_CENTRE:
elif tStyle & BlockFmt.CENTRE:
oStyle.setTextAlign("center")
elif tStyle & self.A_JUSTIFY:
elif tStyle & BlockFmt.JUSTIFY:
oStyle.setTextAlign("justify")
if tStyle & self.A_PBB:
if tStyle & BlockFmt.PBB:
oStyle.setBreakBefore("page")
if tStyle & self.A_PBA:
if tStyle & BlockFmt.PBA:
oStyle.setBreakAfter("page")
if tStyle & self.A_Z_BTMMRG:
if tStyle & BlockFmt.Z_BTMMRG:
oStyle.setMarginBottom("0.000cm")
if tStyle & self.A_Z_TOPMRG:
if tStyle & BlockFmt.Z_TOPMRG:
oStyle.setMarginTop("0.000cm")
if tStyle & self.A_IND_L:
if tStyle & BlockFmt.IND_L:
oStyle.setMarginLeft(self._fBlockIndent)
if tStyle & self.A_IND_R:
if tStyle & BlockFmt.IND_R:
oStyle.setMarginRight(self._fBlockIndent)
# Process Text Types
if tType == self.T_TEXT:
if tType == BlockTyp.TEXT:
# Text indentation is processed here because there is a
# dedicated pre-defined style for it
if tStyle & self.A_IND_T:
if tStyle & BlockFmt.IND_T:
self._addTextPar(xText, S_FIND, oStyle, tText, tFmt=tFormat)
else:
self._addTextPar(xText, S_TEXT, oStyle, tText, tFmt=tFormat)
elif tType == self.T_TITLE:
elif tType == BlockTyp.TITLE:
# Title must be text:p
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._addTextPar(xText, S_TITLE, oStyle, tHead, isHead=False)
elif tType == self.T_HEAD1:
elif tType == BlockTyp.HEAD1:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._addTextPar(xText, S_HEAD1, oStyle, tHead, isHead=True, oLevel="1")
elif tType == self.T_HEAD2:
elif tType == BlockTyp.HEAD2:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._addTextPar(xText, S_HEAD2, oStyle, tHead, isHead=True, oLevel="2")
elif tType == self.T_HEAD3:
elif tType == BlockTyp.HEAD3:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._addTextPar(xText, S_HEAD3, oStyle, tHead, isHead=True, oLevel="3")
elif tType == self.T_HEAD4:
elif tType == BlockTyp.HEAD4:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._addTextPar(xText, S_HEAD4, oStyle, tHead, isHead=True, oLevel="4")
elif tType == self.T_SEP:
elif tType == BlockTyp.SEP:
self._addTextPar(xText, S_SEP, oStyle, tText)
elif tType == self.T_SKIP:
elif tType == BlockTyp.SKIP:
self._addTextPar(xText, S_TEXT, oStyle, "")
elif tType == self.T_SYNOPSIS and self._doSynopsis:
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 == self.T_SHORT and self._doSynopsis:
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 == self.T_COMMENT and self._doComments:
elif tType == BlockTyp.COMMENT and self._doComments:
tTemp, tFmt = self._formatComments(tText, tFormat)
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
elif tType == self.T_KEYWORD and self._doKeywords:
elif tType == BlockTyp.KEYWORD and self._doKeywords:
tTemp, tFmt = self._formatKeywords(tText)
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
@@ -576,7 +578,7 @@ class ToOdt(Tokenizer):
name = self._localLookup("Synopsis" if synopsis else "Short Description")
shift = len(name) + 2
rTxt = f"{name}: {text}"
rFmt: T_Formats = [(0, self.FMT_B_B, ""), (len(name) + 1, self.FMT_B_E, "")]
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
@@ -585,7 +587,7 @@ class ToOdt(Tokenizer):
name = self._localLookup("Comment")
shift = len(name) + 2
rTxt = f"{name}: {text}"
rFmt: T_Formats = [(0, self.FMT_B_B, ""), (len(name) + 1, self.FMT_B_E, "")]
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
@@ -596,7 +598,7 @@ class ToOdt(Tokenizer):
return "", []
rTxt = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: "
rFmt: T_Formats = [(0, self.FMT_B_B, ""), (len(rTxt) - 1, self.FMT_B_E, "")]
rFmt: T_Formats = [(0, TextFmt.B_B, ""), (len(rTxt) - 1, TextFmt.B_E, "")]
if len(bits) > 1:
if bits[0] == nwKeyWords.TAG_KEY:
rTxt += bits[1]
@@ -654,45 +656,45 @@ class ToOdt(Tokenizer):
parProc.appendSpan(tFrag, self._textStyle(xFmt))
# Calculate the change of format
if fFmt == self.FMT_B_B:
if fFmt == TextFmt.B_B:
xFmt |= X_BLD
elif fFmt == self.FMT_B_E:
elif fFmt == TextFmt.B_E:
xFmt &= M_BLD
elif fFmt == self.FMT_I_B:
elif fFmt == TextFmt.I_B:
xFmt |= X_ITA
elif fFmt == self.FMT_I_E:
elif fFmt == TextFmt.I_E:
xFmt &= M_ITA
elif fFmt == self.FMT_D_B:
elif fFmt == TextFmt.D_B:
xFmt |= X_DEL
elif fFmt == self.FMT_D_E:
elif fFmt == TextFmt.D_E:
xFmt &= M_DEL
elif fFmt == self.FMT_U_B:
elif fFmt == TextFmt.U_B:
xFmt |= X_UND
elif fFmt == self.FMT_U_E:
elif fFmt == TextFmt.U_E:
xFmt &= M_UND
elif fFmt == self.FMT_M_B:
elif fFmt == TextFmt.M_B:
xFmt |= X_MRK
elif fFmt == self.FMT_M_E:
elif fFmt == TextFmt.M_E:
xFmt &= M_MRK
elif fFmt == self.FMT_SUP_B:
elif fFmt == TextFmt.SUP_B:
xFmt |= X_SUP
elif fFmt == self.FMT_SUP_E:
elif fFmt == TextFmt.SUP_E:
xFmt &= M_SUP
elif fFmt == self.FMT_SUB_B:
elif fFmt == TextFmt.SUB_B:
xFmt |= X_SUB
elif fFmt == self.FMT_SUB_E:
elif fFmt == TextFmt.SUB_E:
xFmt &= M_SUB
elif fFmt == self.FMT_DL_B:
elif fFmt == TextFmt.DL_B:
xFmt |= X_DLG
elif fFmt == self.FMT_DL_E:
elif fFmt == TextFmt.DL_E:
xFmt &= M_DLG
elif fFmt == self.FMT_ADL_B:
elif fFmt == TextFmt.ADL_B:
xFmt |= X_DLA
elif fFmt == self.FMT_ADL_E:
elif fFmt == TextFmt.ADL_E:
xFmt &= M_DLA
elif fFmt == self.FMT_FNOTE:
elif fFmt == TextFmt.FNOTE:
xNode = self._generateFootnote(fData)
elif fFmt == self.FMT_STRIP:
elif fFmt == TextFmt.STRIP:
pass
else:
pErr += 1
+50 -50
View File
@@ -36,7 +36,7 @@ from PyQt5.QtPrintSupport import QPrinter
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles, nwUnicode
from novelwriter.core.project import NWProject
from novelwriter.formats.tokenizer import T_Formats, Tokenizer
from novelwriter.formats.tokenizer import BlockFmt, BlockTyp, T_Formats, TextFmt, Tokenizer
from novelwriter.types import (
QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight,
QtPageBreakAfter, QtPageBreakBefore, QtTransparent, QtVAlignNormal,
@@ -141,20 +141,20 @@ class ToQTextDocument(Tokenizer):
# ============
self._mHead = {
self.T_TITLE: (mPx * self._marginTitle[0], mPx * self._marginTitle[1]),
self.T_HEAD1: (mPx * self._marginHead1[0], mPx * self._marginHead1[1]),
self.T_HEAD2: (mPx * self._marginHead2[0], mPx * self._marginHead2[1]),
self.T_HEAD3: (mPx * self._marginHead3[0], mPx * self._marginHead3[1]),
self.T_HEAD4: (mPx * self._marginHead4[0], mPx * self._marginHead4[1]),
BlockTyp.TITLE: (mPx * self._marginTitle[0], mPx * self._marginTitle[1]),
BlockTyp.HEAD1: (mPx * self._marginHead1[0], mPx * self._marginHead1[1]),
BlockTyp.HEAD2: (mPx * self._marginHead2[0], mPx * self._marginHead2[1]),
BlockTyp.HEAD3: (mPx * self._marginHead3[0], mPx * self._marginHead3[1]),
BlockTyp.HEAD4: (mPx * self._marginHead4[0], mPx * self._marginHead4[1]),
}
hScale = self._scaleHeads
self._sHead = {
self.T_TITLE: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt,
self.T_HEAD1: (nwStyles.H_SIZES.get(1, 1.0) * fPt) if hScale else fPt,
self.T_HEAD2: (nwStyles.H_SIZES.get(2, 1.0) * fPt) if hScale else fPt,
self.T_HEAD3: (nwStyles.H_SIZES.get(3, 1.0) * fPt) if hScale else fPt,
self.T_HEAD4: (nwStyles.H_SIZES.get(4, 1.0) * fPt) if hScale else fPt,
BlockTyp.TITLE: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt,
BlockTyp.HEAD1: (nwStyles.H_SIZES.get(1, 1.0) * fPt) if hScale else fPt,
BlockTyp.HEAD2: (nwStyles.H_SIZES.get(2, 1.0) * fPt) if hScale else fPt,
BlockTyp.HEAD3: (nwStyles.H_SIZES.get(3, 1.0) * fPt) if hScale else fPt,
BlockTyp.HEAD4: (nwStyles.H_SIZES.get(4, 1.0) * fPt) if hScale else fPt,
}
self._mText = (mPx * self._marginText[0], mPx * self._marginText[1])
@@ -226,33 +226,33 @@ class ToQTextDocument(Tokenizer):
# Styles
bFmt = QTextBlockFormat(self._blockFmt)
if tStyle is not None:
if tStyle & self.A_LEFT:
if tStyle & BlockFmt.LEFT:
bFmt.setAlignment(QtAlignLeft)
elif tStyle & self.A_RIGHT:
elif tStyle & BlockFmt.RIGHT:
bFmt.setAlignment(QtAlignRight)
elif tStyle & self.A_CENTRE:
elif tStyle & BlockFmt.CENTRE:
bFmt.setAlignment(QtAlignCenter)
elif tStyle & self.A_JUSTIFY:
elif tStyle & BlockFmt.JUSTIFY:
bFmt.setAlignment(QtAlignJustify)
if tStyle & self.A_PBB:
if tStyle & BlockFmt.PBB:
bFmt.setPageBreakPolicy(QtPageBreakBefore)
if tStyle & self.A_PBA:
if tStyle & BlockFmt.PBA:
bFmt.setPageBreakPolicy(QtPageBreakAfter)
if tStyle & self.A_Z_BTMMRG:
if tStyle & BlockFmt.Z_BTMMRG:
bFmt.setBottomMargin(0.0)
if tStyle & self.A_Z_TOPMRG:
if tStyle & BlockFmt.Z_TOPMRG:
bFmt.setTopMargin(0.0)
if tStyle & self.A_IND_L:
if tStyle & BlockFmt.IND_L:
bFmt.setLeftMargin(self._mIndent)
if tStyle & self.A_IND_R:
if tStyle & BlockFmt.IND_R:
bFmt.setRightMargin(self._mIndent)
if tStyle & self.A_IND_T:
if tStyle & BlockFmt.IND_T:
bFmt.setTextIndent(self._tIndent)
if tType == self.T_TEXT:
if tType == BlockTyp.TEXT:
newBlock(cursor, bFmt)
self._insertFragments(tText, tFormat, cursor, self._cText)
@@ -261,32 +261,32 @@ class ToQTextDocument(Tokenizer):
newBlock(cursor, bFmt)
cursor.insertText(tText.replace(nwHeadFmt.BR, "\n"), cFmt)
elif tType == self.T_SEP:
elif tType == BlockTyp.SEP:
sFmt = QTextBlockFormat(bFmt)
sFmt.setTopMargin(self._mSep[0])
sFmt.setBottomMargin(self._mSep[1])
newBlock(cursor, sFmt)
cursor.insertText(tText, self._cText)
elif tType == self.T_SKIP:
elif tType == BlockTyp.SKIP:
newBlock(cursor, bFmt)
cursor.insertText(nwUnicode.U_NBSP, self._cText)
elif tType in self.L_SUMMARY and self._doSynopsis:
newBlock(cursor, bFmt)
modifier = self._localLookup(
"Short Description" if tType == self.T_SHORT else "Synopsis"
"Short Description" if tType == BlockTyp.SHORT else "Synopsis"
)
cursor.insertText(f"{modifier}: ", self._cModifier)
self._insertFragments(tText, tFormat, cursor, self._cNote)
elif tType == self.T_COMMENT and self._doComments:
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)
elif tType == self.T_KEYWORD and self._doKeywords:
elif tType == BlockTyp.KEYWORD and self._doKeywords:
newBlock(cursor, bFmt)
self._insertKeywords(tText, cursor)
@@ -317,7 +317,7 @@ class ToQTextDocument(Tokenizer):
cursor = QTextCursor(self._document)
cursor.movePosition(QTextCursor.MoveOperation.End)
bFmt, cFmt = self._genHeadStyle(self.T_HEAD4, -1, self._blockFmt)
bFmt, cFmt = self._genHeadStyle(BlockTyp.HEAD4, -1, self._blockFmt)
newBlock(cursor, bFmt)
cursor.insertText(self._localLookup("Footnotes"), cFmt)
@@ -351,43 +351,43 @@ class ToQTextDocument(Tokenizer):
cursor.insertText(temp[start:pos], cFmt)
# Construct next format
if fmt == self.FMT_B_B:
if fmt == TextFmt.B_B:
cFmt.setFontWeight(self._bold)
elif fmt == self.FMT_B_E:
elif fmt == TextFmt.B_E:
cFmt.setFontWeight(self._normal)
elif fmt == self.FMT_I_B:
elif fmt == TextFmt.I_B:
cFmt.setFontItalic(True)
elif fmt == self.FMT_I_E:
elif fmt == TextFmt.I_E:
cFmt.setFontItalic(False)
elif fmt == self.FMT_D_B:
elif fmt == TextFmt.D_B:
cFmt.setFontStrikeOut(True)
elif fmt == self.FMT_D_E:
elif fmt == TextFmt.D_E:
cFmt.setFontStrikeOut(False)
elif fmt == self.FMT_U_B:
elif fmt == TextFmt.U_B:
cFmt.setFontUnderline(True)
elif fmt == self.FMT_U_E:
elif fmt == TextFmt.U_E:
cFmt.setFontUnderline(False)
elif fmt == self.FMT_M_B:
elif fmt == TextFmt.M_B:
cFmt.setBackground(self._theme.highlight)
elif fmt == self.FMT_M_E:
elif fmt == TextFmt.M_E:
cFmt.setBackground(QtTransparent)
elif fmt == self.FMT_SUP_B:
elif fmt == TextFmt.SUP_B:
cFmt.setVerticalAlignment(QtVAlignSuper)
elif fmt == self.FMT_SUP_E:
elif fmt == TextFmt.SUP_E:
cFmt.setVerticalAlignment(QtVAlignNormal)
elif fmt == self.FMT_SUB_B:
elif fmt == TextFmt.SUB_B:
cFmt.setVerticalAlignment(QtVAlignSub)
elif fmt == self.FMT_SUB_E:
elif fmt == TextFmt.SUB_E:
cFmt.setVerticalAlignment(QtVAlignNormal)
elif fmt == self.FMT_DL_B:
elif fmt == TextFmt.DL_B:
cFmt.setForeground(self._theme.dialog)
elif fmt == self.FMT_DL_E:
elif fmt == TextFmt.DL_E:
cFmt.setForeground(self._theme.text)
elif fmt == self.FMT_ADL_B:
elif fmt == TextFmt.ADL_B:
cFmt.setForeground(self._theme.altdialog)
elif fmt == self.FMT_ADL_E:
elif fmt == TextFmt.ADL_E:
cFmt.setForeground(self._theme.text)
elif fmt == self.FMT_FNOTE:
elif fmt == TextFmt.FNOTE:
xFmt = QTextCharFormat(self._cCode)
xFmt.setVerticalAlignment(QtVAlignSuper)
if data in self._footnotes:
@@ -435,7 +435,7 @@ class ToQTextDocument(Tokenizer):
cursor.insertText(", ", self._cText)
return
def _genHeadStyle(self, hType: int, nHead: int, rFmt: QTextBlockFormat) -> T_TextStyle:
def _genHeadStyle(self, hType: BlockTyp, nHead: int, rFmt: QTextBlockFormat) -> T_TextStyle:
"""Generate a heading style set."""
mTop, mBottom = self._mHead.get(hType, (0.0, 0.0))
@@ -446,7 +446,7 @@ class ToQTextDocument(Tokenizer):
self._cTitle = QTextCharFormat(self._cText)
self._cTitle.setFontWeight(self._bold if self._boldHeads else self._normal)
hCol = self._colorHeads and hType != self.T_TITLE
hCol = self._colorHeads and hType != BlockTyp.TITLE
cFmt = QTextCharFormat(self._cText)
cFmt.setForeground(self._theme.head if hCol else self._theme.text)
cFmt.setFontWeight(self._bold if self._boldHeads else self._normal)
+24 -23
View File
@@ -35,6 +35,7 @@ from novelwriter.formats.todocx import (
S_FNOTE, S_HEAD1, S_HEAD2, S_HEAD3, S_HEAD4, S_META, S_NORM, S_SEP,
S_TITLE, ToDocX, _mkTag, _wTag
)
from novelwriter.formats.tokenizer import BlockFmt, BlockTyp
from tests.tools import DOCX_IGNORE, cmpFiles
@@ -70,7 +71,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Normal Text
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TEXT, 0, "Hello World", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.TEXT, 0, "Hello World", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -80,7 +81,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Title
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TITLE, 0, "Hello World", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.TITLE, 0, "Hello World", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -90,7 +91,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Heading Level 1
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_HEAD1, 0, "Hello World", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.HEAD1, 0, "Hello World", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -100,7 +101,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Heading Level 2
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_HEAD2, 0, "Hello World", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.HEAD2, 0, "Hello World", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -110,7 +111,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Heading Level 3
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_HEAD3, 0, "Hello World", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.HEAD3, 0, "Hello World", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -120,7 +121,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Heading Level 4
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_HEAD4, 0, "Hello World", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.HEAD4, 0, "Hello World", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -130,7 +131,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Separator
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_SEP, 0, "* * *", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.SEP, 0, "* * *", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -140,7 +141,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Empty Paragraph
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_SKIP, 0, "* * *", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.SKIP, 0, "* * *", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -149,7 +150,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Synopsis
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_SYNOPSIS, 0, "Hello World", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.SYNOPSIS, 0, "Hello World", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -161,7 +162,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Short
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_SHORT, 0, "Hello World", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.SHORT, 0, "Hello World", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -173,7 +174,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Comment
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_COMMENT, 0, "Hello World", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.COMMENT, 0, "Hello World", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -185,7 +186,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Tags and References (Single)
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_KEYWORD, 0, "tag: Stuff", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.KEYWORD, 0, "tag: Stuff", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -197,7 +198,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Tags and References (Multiple)
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_KEYWORD, 0, "char: Jane, John", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.KEYWORD, 0, "char: Jane, John", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -209,7 +210,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Tags and References (Invalid)
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_KEYWORD, 0, "stuff: Stuff", [], doc.A_NONE)]
doc._tokens = [(BlockTyp.KEYWORD, 0, "stuff: Stuff", [], BlockFmt.NONE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -229,7 +230,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
# Left Align
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TEXT, 0, "Hello World", [], doc.A_LEFT)]
doc._tokens = [(BlockTyp.TEXT, 0, "Hello World", [], BlockFmt.LEFT)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -239,7 +240,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
# Right Align
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TEXT, 0, "Hello World", [], doc.A_RIGHT)]
doc._tokens = [(BlockTyp.TEXT, 0, "Hello World", [], BlockFmt.RIGHT)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -249,7 +250,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
# Center Align
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TEXT, 0, "Hello World", [], doc.A_CENTRE)]
doc._tokens = [(BlockTyp.TEXT, 0, "Hello World", [], BlockFmt.CENTRE)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -259,7 +260,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
# Justify
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TEXT, 0, "Hello World", [], doc.A_JUSTIFY)]
doc._tokens = [(BlockTyp.TEXT, 0, "Hello World", [], BlockFmt.JUSTIFY)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -269,7 +270,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
# Page Break Before
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TEXT, 0, "Hello World", [], doc.A_PBB)]
doc._tokens = [(BlockTyp.TEXT, 0, "Hello World", [], BlockFmt.PBB)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -281,7 +282,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
# Page Break After
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TEXT, 0, "Hello World", [], doc.A_PBA)]
doc._tokens = [(BlockTyp.TEXT, 0, "Hello World", [], BlockFmt.PBA)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -293,7 +294,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
# Zero Margins
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TEXT, 0, "Hello World", [], doc.A_Z_TOPMRG | doc.A_Z_BTMMRG)]
doc._tokens = [(BlockTyp.TEXT, 0, "Hello World", [], BlockFmt.Z_TOPMRG | BlockFmt.Z_BTMMRG)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -304,7 +305,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
# Indent
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TEXT, 0, "Hello World", [], doc.A_IND_L | doc.A_IND_R)]
doc._tokens = [(BlockTyp.TEXT, 0, "Hello World", [], BlockFmt.IND_L | BlockFmt.IND_R)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
@@ -315,7 +316,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
# First Line Indent
xTest = ET.Element(_wTag("body"))
doc._tokens = [(doc.T_TEXT, 0, "Hello World", [], doc.A_IND_T)]
doc._tokens = [(BlockTyp.TEXT, 0, "Hello World", [], BlockFmt.IND_T)]
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
+14 -13
View File
@@ -27,6 +27,7 @@ import pytest
from novelwriter import CONFIG
from novelwriter.core.project import NWProject
from novelwriter.formats.tohtml import ToHtml
from novelwriter.formats.tokenizer import BlockFmt, BlockTyp
@pytest.mark.core
@@ -359,7 +360,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Title
html._tokens = [
(html.T_TITLE, 1, "A Title", [], html.A_PBB | html.A_CENTRE),
(BlockTyp.TITLE, 1, "A Title", [], BlockFmt.PBB | BlockFmt.CENTRE),
]
html.doConvert()
assert html.result == (
@@ -369,7 +370,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Unnumbered
html._tokens = [
(html.T_HEAD2, 1, "Prologue", [], html.A_PBB),
(BlockTyp.HEAD2, 1, "Prologue", [], BlockFmt.PBB),
]
html.doConvert()
assert html.result == (
@@ -382,14 +383,14 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Separator
html._tokens = [
(html.T_SEP, 1, "* * *", [], html.A_CENTRE),
(BlockTyp.SEP, 1, "* * *", [], BlockFmt.CENTRE),
]
html.doConvert()
assert html.result == "<p class='sep' style='text-align: center;'>* * *</p>\n"
# Skip
html._tokens = [
(html.T_SKIP, 1, "", [], html.A_NONE),
(BlockTyp.SKIP, 1, "", [], BlockFmt.NONE),
]
html.doConvert()
assert html.result == "<p class='skip'>&nbsp;</p>\n"
@@ -402,7 +403,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Align Left
html.setStyles(False)
html._tokens = [
(html.T_HEAD1, 1, "A Title", [], html.A_LEFT),
(BlockTyp.HEAD1, 1, "A Title", [], BlockFmt.LEFT),
]
html.doConvert()
assert html.result == (
@@ -413,7 +414,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Align Left
html._tokens = [
(html.T_HEAD1, 1, "A Title", [], html.A_LEFT),
(BlockTyp.HEAD1, 1, "A Title", [], BlockFmt.LEFT),
]
html.doConvert()
assert html.result == (
@@ -422,7 +423,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Align Right
html._tokens = [
(html.T_HEAD1, 1, "A Title", [], html.A_RIGHT),
(BlockTyp.HEAD1, 1, "A Title", [], BlockFmt.RIGHT),
]
html.doConvert()
assert html.result == (
@@ -431,7 +432,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Align Centre
html._tokens = [
(html.T_HEAD1, 1, "A Title", [], html.A_CENTRE),
(BlockTyp.HEAD1, 1, "A Title", [], BlockFmt.CENTRE),
]
html.doConvert()
assert html.result == (
@@ -440,7 +441,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Align Justify
html._tokens = [
(html.T_HEAD1, 1, "A Title", [], html.A_JUSTIFY),
(BlockTyp.HEAD1, 1, "A Title", [], BlockFmt.JUSTIFY),
]
html.doConvert()
assert html.result == (
@@ -452,7 +453,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Page Break Always
html._tokens = [
(html.T_HEAD1, 1, "A Title", [], html.A_PBB | html.A_PBA),
(BlockTyp.HEAD1, 1, "A Title", [], BlockFmt.PBB | BlockFmt.PBA),
]
html.doConvert()
assert html.result == (
@@ -465,7 +466,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Indent Left
html._tokens = [
(html.T_TEXT, 1, "Some text ...", [], html.A_IND_L),
(BlockTyp.TEXT, 1, "Some text ...", [], BlockFmt.IND_L),
]
html.doConvert()
assert html.result == (
@@ -474,7 +475,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Indent Right
html._tokens = [
(html.T_TEXT, 1, "Some text ...", [], html.A_IND_R),
(BlockTyp.TEXT, 1, "Some text ...", [], BlockFmt.IND_R),
]
html.doConvert()
assert html.result == (
@@ -483,7 +484,7 @@ def testFmtToHtml_ConvertDirect(mockGUI):
# Text Indent
html._tokens = [
(html.T_TEXT, 1, "Some text ...", [], html.A_IND_T),
(BlockTyp.TEXT, 1, "Some text ...", [], BlockFmt.IND_T),
]
html.doConvert()
assert html.result == (
File diff suppressed because it is too large Load Diff
+8 -7
View File
@@ -23,6 +23,7 @@ from __future__ import annotations
import pytest
from novelwriter.core.project import NWProject
from novelwriter.formats.tokenizer import BlockFmt, BlockTyp
from novelwriter.formats.tomarkdown import ToMarkdown
@@ -220,7 +221,7 @@ def testFmtToMarkdown_ConvertDirect(mockGUI):
# Title
toMD._tokens = [
(toMD.T_TITLE, 1, "A Title", [], toMD.A_PBB | toMD.A_CENTRE),
(BlockTyp.TITLE, 1, "A Title", [], BlockFmt.PBB | BlockFmt.CENTRE),
]
toMD.doConvert()
assert toMD.result == "# A Title\n\n"
@@ -230,14 +231,14 @@ def testFmtToMarkdown_ConvertDirect(mockGUI):
# Separator
toMD._tokens = [
(toMD.T_SEP, 1, "* * *", [], toMD.A_CENTRE),
(BlockTyp.SEP, 1, "* * *", [], BlockFmt.CENTRE),
]
toMD.doConvert()
assert toMD.result == "* * *\n\n"
# Skip
toMD._tokens = [
(toMD.T_SKIP, 1, "", [], toMD.A_NONE),
(BlockTyp.SKIP, 1, "", [], BlockFmt.NONE),
]
toMD.doConvert()
assert toMD.result == "\n\n"
@@ -300,7 +301,7 @@ def testFmtToMarkdown_Format(mockGUI):
project = NWProject()
toMD = ToMarkdown(project, False)
assert toMD._formatKeywords("", toMD.A_NONE) == ""
assert toMD._formatKeywords("tag: Jane", toMD.A_NONE) == "**Tag:** Jane\n\n"
assert toMD._formatKeywords("tag: Jane, John", toMD.A_NONE) == "**Tag:** Jane, John\n\n"
assert toMD._formatKeywords("tag: Jane", toMD.A_Z_BTMMRG) == "**Tag:** Jane \n"
assert toMD._formatKeywords("", BlockFmt.NONE) == ""
assert toMD._formatKeywords("tag: Jane", BlockFmt.NONE) == "**Tag:** Jane\n\n"
assert toMD._formatKeywords("tag: Jane, John", BlockFmt.NONE) == "**Tag:** Jane, John\n\n"
assert toMD._formatKeywords("tag: Jane", BlockFmt.Z_BTMMRG) == "**Tag:** Jane \n"
+16 -15
View File
@@ -30,6 +30,7 @@ import pytest
from novelwriter.common import xmlIndent
from novelwriter.constants import nwHeadFmt
from novelwriter.core.project import NWProject
from novelwriter.formats.tokenizer import BlockFmt, BlockTyp, TextFmt
from novelwriter.formats.toodt import ODTParagraphStyle, ODTTextStyle, ToOdt, XMLParagraph, _mkTag
from tests.tools import ODT_IGNORE, cmpFiles
@@ -183,7 +184,7 @@ def testFmtToOdt_TextFormatting(mockGUI):
# Formatted Text
text = "A bold word"
fmt = [(2, odt.FMT_B_B, ""), (6, odt.FMT_B_E, "")]
fmt = [(2, TextFmt.B_B, ""), (6, TextFmt.B_E, "")]
xTest = ET.Element(_mkTag("office", "text"))
odt._addTextPar(xTest, "Standard", oStyle, text, tFmt=fmt)
assert odt.errData == []
@@ -196,7 +197,7 @@ def testFmtToOdt_TextFormatting(mockGUI):
# Incorrectly Formatted Text
text = "A few words"
fmt = [(2, odt.FMT_B_B, ""), (5, odt.FMT_B_E, ""), (7, 99999, "")]
fmt = [(2, TextFmt.B_B, ""), (5, TextFmt.B_E, ""), (7, 99999, "")]
xTest = ET.Element(_mkTag("office", "text"))
odt._addTextPar(xTest, "Standard", oStyle, text, tFmt=fmt)
assert odt.errData == ["Unknown format tag encountered"]
@@ -210,7 +211,7 @@ def testFmtToOdt_TextFormatting(mockGUI):
# Unclosed format
text = "A bold word"
fmt = [(2, odt.FMT_B_B, "")]
fmt = [(2, TextFmt.B_B, "")]
xTest = ET.Element(_mkTag("office", "text"))
odt._addTextPar(xTest, "Standard", oStyle, text, tFmt=fmt)
assert odt.errData == []
@@ -245,7 +246,7 @@ def testFmtToOdt_DialogueFormatting(mockGUI):
# Regular dialogue
text = "Text with 'dialogue in it.'"
fmt = [(10, odt.FMT_DL_B, ""), (27, odt.FMT_DL_E, "")]
fmt = [(10, TextFmt.DL_B, ""), (27, TextFmt.DL_E, "")]
xTest = ET.Element(_mkTag("office", "text"))
odt._addTextPar(xTest, "Standard", oStyle, text, tFmt=fmt)
assert odt.errData == []
@@ -258,7 +259,7 @@ def testFmtToOdt_DialogueFormatting(mockGUI):
# Alternative dialogue
text = "Text with ::dialogue in it.::"
fmt = [(10, odt.FMT_ADL_B, ""), (29, odt.FMT_ADL_E, "")]
fmt = [(10, TextFmt.ADL_B, ""), (29, TextFmt.ADL_E, "")]
xTest = ET.Element(_mkTag("office", "text"))
odt._addTextPar(xTest, "Standard", oStyle, text, tFmt=fmt)
assert odt.errData == []
@@ -719,7 +720,7 @@ def testFmtToOdt_ConvertDirect(mockGUI):
# Justified
doc = ToOdt(project, isFlat=True)
doc._tokens = [
(doc.T_TEXT, 1, "This is a paragraph", [], doc.A_JUSTIFY),
(BlockTyp.TEXT, 1, "This is a paragraph", [], BlockFmt.JUSTIFY),
]
doc.initDocument()
doc.doConvert()
@@ -739,7 +740,7 @@ def testFmtToOdt_ConvertDirect(mockGUI):
# Page Break After
doc = ToOdt(project, isFlat=True)
doc._tokens = [
(doc.T_TEXT, 1, "This is a paragraph", [], doc.A_PBA),
(BlockTyp.TEXT, 1, "This is a paragraph", [], BlockFmt.PBA),
]
doc.initDocument()
doc.doConvert()
@@ -894,28 +895,28 @@ def testFmtToOdt_SpecialFormats(mockGUI):
project = NWProject()
odt = ToOdt(project, isFlat=True)
assert odt._formatSynopsis("synopsis text", [(9, ToOdt.FMT_STRIP, "")], True) == (
assert odt._formatSynopsis("synopsis text", [(9, TextFmt.STRIP, "")], True) == (
"Synopsis: synopsis text", [
(0, ToOdt.FMT_B_B, ""), (9, ToOdt.FMT_B_E, ""), (19, ToOdt.FMT_STRIP, "")
(0, TextFmt.B_B, ""), (9, TextFmt.B_E, ""), (19, TextFmt.STRIP, "")
]
)
assert odt._formatSynopsis("short text", [(6, ToOdt.FMT_STRIP, "")], False) == (
assert odt._formatSynopsis("short text", [(6, TextFmt.STRIP, "")], False) == (
"Short Description: short text", [
(0, ToOdt.FMT_B_B, ""), (18, ToOdt.FMT_B_E, ""), (25, ToOdt.FMT_STRIP, "")
(0, TextFmt.B_B, ""), (18, TextFmt.B_E, ""), (25, TextFmt.STRIP, "")
]
)
assert odt._formatComments("comment text", [(8, ToOdt.FMT_STRIP, "")]) == (
assert odt._formatComments("comment text", [(8, TextFmt.STRIP, "")]) == (
"Comment: comment text", [
(0, ToOdt.FMT_B_B, ""), (8, ToOdt.FMT_B_E, ""), (17, ToOdt.FMT_STRIP, "")
(0, TextFmt.B_B, ""), (8, TextFmt.B_E, ""), (17, TextFmt.STRIP, "")
]
)
assert odt._formatKeywords("") == ("", [])
assert odt._formatKeywords("tag: Jane") == (
"Tag: Jane", [(0, ToOdt.FMT_B_B, ""), (4, ToOdt.FMT_B_E, "")]
"Tag: Jane", [(0, TextFmt.B_B, ""), (4, TextFmt.B_E, "")]
)
assert odt._formatKeywords("char: Bod, Jane") == (
"Characters: Bod, Jane", [(0, ToOdt.FMT_B_B, ""), (11, ToOdt.FMT_B_E, "")]
"Characters: Bod, Jane", [(0, TextFmt.B_B, ""), (11, TextFmt.B_E, "")]
)
+18 -17
View File
@@ -27,6 +27,7 @@ from PyQt5.QtGui import QTextBlock, QTextCharFormat, QTextCursor
from novelwriter import CONFIG
from novelwriter.constants import nwUnicode
from novelwriter.core.project import NWProject
from novelwriter.formats.tokenizer import BlockFmt, BlockTyp
from novelwriter.formats.toqdoc import TextDocumentTheme, ToQTextDocument
from novelwriter.types import (
QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight,
@@ -68,55 +69,55 @@ def testFmtToQTextDocument_ConvertHeaders(mockGUI):
block = qdoc.document.findBlockByNumber(0)
assert block.text() == "Title"
bFmt = block.blockFormat()
assert bFmt.topMargin() == qdoc._mHead[qdoc.T_TITLE][0]
assert bFmt.bottomMargin() == qdoc._mHead[qdoc.T_TITLE][1]
assert bFmt.topMargin() == qdoc._mHead[BlockTyp.TITLE][0]
assert bFmt.bottomMargin() == qdoc._mHead[BlockTyp.TITLE][1]
cFmt = charFmtInBlock(block, 1)
assert cFmt.fontWeight() == qdoc._bold
assert cFmt.fontPointSize() == qdoc._sHead[qdoc.T_TITLE]
assert cFmt.fontPointSize() == qdoc._sHead[BlockTyp.TITLE]
assert cFmt.foreground().color() == THEME.text
# Partition
block = qdoc.document.findBlockByNumber(1)
assert block.text() == "Partition"
bFmt = block.blockFormat()
assert bFmt.topMargin() == qdoc._mHead[qdoc.T_HEAD1][0]
assert bFmt.bottomMargin() == qdoc._mHead[qdoc.T_HEAD1][1]
assert bFmt.topMargin() == qdoc._mHead[BlockTyp.HEAD1][0]
assert bFmt.bottomMargin() == qdoc._mHead[BlockTyp.HEAD1][1]
cFmt = charFmtInBlock(block, 1)
assert cFmt.fontWeight() == qdoc._bold
assert cFmt.fontPointSize() == qdoc._sHead[qdoc.T_HEAD1]
assert cFmt.fontPointSize() == qdoc._sHead[BlockTyp.HEAD1]
assert cFmt.foreground().color() == THEME.head
# Chapter
block = qdoc.document.findBlockByNumber(2)
assert block.text() == "Chapter"
bFmt = block.blockFormat()
assert bFmt.topMargin() == qdoc._mHead[qdoc.T_HEAD2][0]
assert bFmt.bottomMargin() == qdoc._mHead[qdoc.T_HEAD2][1]
assert bFmt.topMargin() == qdoc._mHead[BlockTyp.HEAD2][0]
assert bFmt.bottomMargin() == qdoc._mHead[BlockTyp.HEAD2][1]
cFmt = charFmtInBlock(block, 1)
assert cFmt.fontWeight() == qdoc._bold
assert cFmt.fontPointSize() == qdoc._sHead[qdoc.T_HEAD2]
assert cFmt.fontPointSize() == qdoc._sHead[BlockTyp.HEAD2]
assert cFmt.foreground().color() == THEME.head
# Scene
block = qdoc.document.findBlockByNumber(3)
assert block.text() == "Scene"
bFmt = block.blockFormat()
assert bFmt.topMargin() == qdoc._mHead[qdoc.T_HEAD3][0]
assert bFmt.bottomMargin() == qdoc._mHead[qdoc.T_HEAD3][1]
assert bFmt.topMargin() == qdoc._mHead[BlockTyp.HEAD3][0]
assert bFmt.bottomMargin() == qdoc._mHead[BlockTyp.HEAD3][1]
cFmt = charFmtInBlock(block, 1)
assert cFmt.fontWeight() == qdoc._bold
assert cFmt.fontPointSize() == qdoc._sHead[qdoc.T_HEAD3]
assert cFmt.fontPointSize() == qdoc._sHead[BlockTyp.HEAD3]
assert cFmt.foreground().color() == THEME.head
# Section
block = qdoc.document.findBlockByNumber(4)
assert block.text() == "Section"
bFmt = block.blockFormat()
assert bFmt.topMargin() == qdoc._mHead[qdoc.T_HEAD4][0]
assert bFmt.bottomMargin() == qdoc._mHead[qdoc.T_HEAD4][1]
assert bFmt.topMargin() == qdoc._mHead[BlockTyp.HEAD4][0]
assert bFmt.bottomMargin() == qdoc._mHead[BlockTyp.HEAD4][1]
cFmt = charFmtInBlock(block, 1)
assert cFmt.fontWeight() == qdoc._bold
assert cFmt.fontPointSize() == qdoc._sHead[qdoc.T_HEAD4]
assert cFmt.fontPointSize() == qdoc._sHead[BlockTyp.HEAD4]
assert cFmt.foreground().color() == THEME.head
@@ -410,8 +411,8 @@ def testFmtToQTextDocument_TextBlockFormats(mockGUI):
qdoc.document.clear()
qdoc._tokens = [
(qdoc.T_TEXT, 1, "This is justified", [], qdoc.A_JUSTIFY),
(qdoc.T_TEXT, 1, "This has a page break", [], qdoc.A_PBA),
(BlockTyp.TEXT, 1, "This is justified", [], BlockFmt.JUSTIFY),
(BlockTyp.TEXT, 1, "This has a page break", [], BlockFmt.PBA),
]
qdoc.doConvert()
assert qdoc.document.blockCount() == 2