Add more formatting options for manuscript builds (#1723)

This commit is contained in:
Veronica Berglyd Olsen
2024-03-02 15:42:12 +01:00
committed by GitHub
11 changed files with 630 additions and 83 deletions
+14
View File
@@ -59,10 +59,17 @@ SETTINGS_TEMPLATE = {
"headings.fmtSection": (str, ""), "headings.fmtSection": (str, ""),
"headings.hideScene": (bool, False), "headings.hideScene": (bool, False),
"headings.hideSection": (bool, True), "headings.hideSection": (bool, True),
"headings.centerTitle": (bool, True),
"headings.centerChapter": (bool, False),
"headings.centerScene": (bool, False),
"headings.breakTitle": (bool, True),
"headings.breakChapter": (bool, True),
"headings.breakScene": (bool, False),
"text.includeSynopsis": (bool, False), "text.includeSynopsis": (bool, False),
"text.includeComments": (bool, False), "text.includeComments": (bool, False),
"text.includeKeywords": (bool, False), "text.includeKeywords": (bool, False),
"text.includeBodyText": (bool, True), "text.includeBodyText": (bool, True),
"text.ignoredKeywords": (str, ""),
"text.addNoteHeadings": (bool, True), "text.addNoteHeadings": (bool, True),
"format.textFont": (str, CONFIG.textFont), "format.textFont": (str, CONFIG.textFont),
"format.textSize": (int, 12), "format.textSize": (int, 12),
@@ -81,7 +88,9 @@ SETTINGS_TEMPLATE = {
"odt.addColours": (bool, True), "odt.addColours": (bool, True),
"odt.pageHeader": (str, nwHeadFmt.ODT_AUTO), "odt.pageHeader": (str, nwHeadFmt.ODT_AUTO),
"odt.pageCountOffset": (int, 0), "odt.pageCountOffset": (int, 0),
"md.preserveBreaks": (bool, True),
"html.addStyles": (bool, True), "html.addStyles": (bool, True),
"html.preserveTabs": (bool, False),
} }
SETTINGS_LABELS = { SETTINGS_LABELS = {
@@ -104,6 +113,7 @@ SETTINGS_LABELS = {
"text.includeComments": QT_TRANSLATE_NOOP("Builds", "Include Comments"), "text.includeComments": QT_TRANSLATE_NOOP("Builds", "Include Comments"),
"text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"), "text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"),
"text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"), "text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"),
"text.ignoredKeywords": QT_TRANSLATE_NOOP("Builds", "Ignore These Keywords"),
"text.grpInsert": QT_TRANSLATE_NOOP("Builds", "Insert Content"), "text.grpInsert": QT_TRANSLATE_NOOP("Builds", "Insert Content"),
"text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"), "text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
@@ -130,8 +140,12 @@ SETTINGS_LABELS = {
"odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"), "odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
"odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"), "odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"),
"md": QT_TRANSLATE_NOOP("Builds", "Markdown (.md)"),
"md.preserveBreaks": QT_TRANSLATE_NOOP("Builds", "Preserve Hard Line Breaks"),
"html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"), "html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"),
"html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"), "html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
"html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"),
} }
+36 -5
View File
@@ -52,15 +52,16 @@ class NWBuildDocument:
manuscript, based on a build definition object (BuildSettings). manuscript, based on a build definition object (BuildSettings).
""" """
__slots__ = ("_project", "_build", "_queue", "_error", "_cache", "_count") __slots__ = ("_project", "_build", "_queue", "_error", "_cache", "_count", "_preview")
def __init__(self, project: NWProject, build: BuildSettings, doCount: bool = False) -> None: def __init__(self, project: NWProject, build: BuildSettings) -> None:
self._project = project self._project = project
self._build = build self._build = build
self._queue = [] self._queue = []
self._error = None self._error = None
self._cache = None self._cache = None
self._count = doCount self._count = False
self._preview = False
return return
## ##
@@ -80,6 +81,21 @@ class NWBuildDocument:
""" """
return self._cache return self._cache
##
# Setters
##
def setCountEnabled(self, state: bool) -> None:
"""Turn on/off stats counting for builds."""
self._count = state
return
def setPreviewMode(self, state: bool) -> None:
"""Set the preview mode of the build. Implies count mode."""
self._preview = state
self._count = state
return
## ##
# Special Methods # Special Methods
## ##
@@ -161,7 +177,7 @@ class NWBuildDocument:
else: else:
yield i, False yield i, False
if self._build.getBool("format.replaceTabs"): if not (self._build.getBool("html.preserveTabs") or self._preview):
makeObj.replaceTabs() makeObj.replaceTabs()
self._error = None self._error = None
@@ -192,6 +208,8 @@ class NWBuildDocument:
if self._build.getBool("format.replaceTabs"): if self._build.getBool("format.replaceTabs"):
makeObj.replaceTabs(nSpaces=4, spaceChar=" ") makeObj.replaceTabs(nSpaces=4, spaceChar=" ")
makeObj.setPreserveBreaks(self._build.getBool("md.preserveBreaks"))
for i, tHandle in enumerate(self._queue): for i, tHandle in enumerate(self._queue):
self._error = None self._error = None
if filtered.get(tHandle, (False, 0))[0]: if filtered.get(tHandle, (False, 0))[0]:
@@ -268,15 +286,28 @@ class NWBuildDocument:
self._build.getStr("headings.fmtSection"), self._build.getStr("headings.fmtSection"),
self._build.getBool("headings.hideSection") self._build.getBool("headings.hideSection")
) )
bldObj.setTitleStyle(
self._build.getBool("headings.centerTitle"),
self._build.getBool("headings.breakTitle")
)
bldObj.setChapterStyle(
self._build.getBool("headings.centerChapter"),
self._build.getBool("headings.breakChapter")
)
bldObj.setSceneStyle(
self._build.getBool("headings.centerScene"),
self._build.getBool("headings.breakScene")
)
bldObj.setFont(fontFamily, textSize, textFixed) bldObj.setFont(fontFamily, textSize, textFixed)
bldObj.setJustify(self._build.getBool("format.justifyText")) bldObj.setJustify(self._build.getBool("format.justifyText"))
bldObj.setLineHeight(self._build.getFloat("format.lineHeight")) bldObj.setLineHeight(self._build.getFloat("format.lineHeight"))
bldObj.setBodyText(self._build.getBool("text.includeBodyText"))
bldObj.setSynopsis(self._build.getBool("text.includeSynopsis")) bldObj.setSynopsis(self._build.getBool("text.includeSynopsis"))
bldObj.setComments(self._build.getBool("text.includeComments")) bldObj.setComments(self._build.getBool("text.includeComments"))
bldObj.setKeywords(self._build.getBool("text.includeKeywords")) bldObj.setKeywords(self._build.getBool("text.includeKeywords"))
bldObj.setBodyText(self._build.getBool("text.includeBodyText")) bldObj.setIgnoredKeywords(self._build.getStr("text.ignoredKeywords"))
if isinstance(bldObj, ToHtml): if isinstance(bldObj, ToHtml):
bldObj.setStyles(self._build.getBool("html.addStyles")) bldObj.setStyles(self._build.getBool("html.addStyles"))
+72 -44
View File
@@ -130,16 +130,17 @@ class Tokenizer(ABC):
self._tokens: list[tuple[int, int, str, list[tuple[int, int]], int]] = [] self._tokens: list[tuple[int, int, str, list[tuple[int, int]], int]] = []
# User Settings # User Settings
self._textFont = "Serif" # Output text font self._textFont = "Serif" # Output text font
self._textSize = 11 # Output text size self._textSize = 11 # Output text size
self._textFixed = False # Fixed width text self._textFixed = False # Fixed width text
self._lineHeight = 1.15 # Line height in units of em self._lineHeight = 1.15 # Line height in units of em
self._blockIndent = 4.00 # Block indent in units of em self._blockIndent = 4.00 # Block indent in units of em
self._doJustify = False # Justify text self._doJustify = False # Justify text
self._doBodyText = True # Include body text self._doBodyText = True # Include body text
self._doSynopsis = False # Also process synopsis comments self._doSynopsis = False # Also process synopsis comments
self._doComments = False # Also process comments self._doComments = False # Also process comments
self._doKeywords = False # Also process keywords like tags and references self._doKeywords = False # Also process keywords like tags and references
self._skipKeywords = set() # Keywords to ignore
# Margins # Margins
self._marginTitle = (1.000, 0.500) self._marginTitle = (1.000, 0.500)
@@ -162,6 +163,10 @@ class Tokenizer(ABC):
self._linkHeaders = False # Add an anchor before headers self._linkHeaders = False # Add an anchor before headers
self._titleStyle = self.A_CENTRE | self.A_PBB
self._chapterStyle = self.A_PBB
self._sceneStyle = self.A_NONE
# Instance Variables # Instance Variables
self._hFormatter = HeadingFormatter(self._project) self._hFormatter = HeadingFormatter(self._project)
self._skipSeparator = False # Flag to indicate that we skip the scene separator self._skipSeparator = False # Flag to indicate that we skip the scene separator
@@ -171,6 +176,7 @@ class Tokenizer(ABC):
self._isNovel = False # Document is a novel document self._isNovel = False # Document is a novel document
self._isNote = False # Document is a project note self._isNote = False # Document is a project note
self._isFirst = True # Document is the first in a set self._isFirst = True # Document is the first in a set
self._noBreak = False # Don't allow an initial break when formatting headers
# Error Handling # Error Handling
self._errData = [] self._errData = []
@@ -255,6 +261,27 @@ class Tokenizer(ABC):
self._hideSection = hide self._hideSection = hide
return return
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)
)
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)
)
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)
)
return
def setFont(self, family: str, size: int, isFixed: bool = False) -> None: def setFont(self, family: str, size: int, isFixed: bool = False) -> None:
"""Set the build font.""" """Set the build font."""
self._textFont = family self._textFont = family
@@ -337,6 +364,11 @@ class Tokenizer(ABC):
self._doKeywords = state self._doKeywords = state
return return
def setIgnoredKeywords(self, keywords: str) -> None:
"""Comma separated string of keywords to ignore."""
self._skipKeywords = set(x.lower().strip() for x in keywords.split(","))
return
def setKeepMarkdown(self, state: bool) -> None: def setKeepMarkdown(self, state: bool) -> None:
"""Keep original markdown during build.""" """Keep original markdown during build."""
self._keepMarkdown = state self._keepMarkdown = state
@@ -504,31 +536,26 @@ class Tokenizer(ABC):
tmpMarkdown.append("%s\n" % aLine) tmpMarkdown.append("%s\n" % aLine)
elif aLine[0] == "@": elif aLine[0] == "@":
self._tokens.append(( valid, bits, _ = self._project.index.scanThis(aLine)
self.T_KEYWORD, nHead, aLine[1:].strip(), [], sAlign if valid and bits and bits[0] not in self._skipKeywords:
)) self._tokens.append((
if self._doKeywords and self._keepMarkdown: self.T_KEYWORD, nHead, aLine[1:].strip(), [], sAlign
tmpMarkdown.append("%s\n" % aLine) ))
if self._doKeywords and self._keepMarkdown:
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:2] == "# ": elif aLine[:2] == "# ":
if self._isNovel:
sAlign |= self.A_CENTRE
sAlign |= self.A_PBB
nHead += 1 nHead += 1
self._tokens.append(( self._tokens.append((
self.T_HEAD1, nHead, aLine[2:].strip(), [], sAlign self.T_HEAD1, nHead, aLine[2:].strip(), [], self.A_NONE
)) ))
if self._keepMarkdown: if self._keepMarkdown:
tmpMarkdown.append("%s\n" % aLine) tmpMarkdown.append("%s\n" % aLine)
elif aLine[:3] == "## ": elif aLine[:3] == "## ":
if self._isNovel:
sAlign |= self.A_PBB
nHead += 1 nHead += 1
self._tokens.append(( self._tokens.append((
self.T_HEAD2, nHead, aLine[3:].strip(), [], sAlign self.T_HEAD2, nHead, aLine[3:].strip(), [], self.A_NONE
)) ))
if self._keepMarkdown: if self._keepMarkdown:
tmpMarkdown.append("%s\n" % aLine) tmpMarkdown.append("%s\n" % aLine)
@@ -536,7 +563,7 @@ class Tokenizer(ABC):
elif aLine[:4] == "### ": elif aLine[:4] == "### ":
nHead += 1 nHead += 1
self._tokens.append(( self._tokens.append((
self.T_HEAD3, nHead, aLine[4:].strip(), [], sAlign self.T_HEAD3, nHead, aLine[4:].strip(), [], self.A_NONE
)) ))
if self._keepMarkdown: if self._keepMarkdown:
tmpMarkdown.append("%s\n" % aLine) tmpMarkdown.append("%s\n" % aLine)
@@ -544,34 +571,25 @@ class Tokenizer(ABC):
elif aLine[:5] == "#### ": elif aLine[:5] == "#### ":
nHead += 1 nHead += 1
self._tokens.append(( self._tokens.append((
self.T_HEAD4, nHead, aLine[5:].strip(), [], sAlign self.T_HEAD4, nHead, aLine[5:].strip(), [], self.A_NONE
)) ))
if self._keepMarkdown: if self._keepMarkdown:
tmpMarkdown.append("%s\n" % aLine) tmpMarkdown.append("%s\n" % aLine)
elif aLine[:3] == "#! ": elif aLine[:3] == "#! ":
nHead += 1 nHead += 1
if self._isNovel:
tStyle = self.T_TITLE
else:
tStyle = self.T_HEAD1
self._tokens.append(( self._tokens.append((
tStyle, nHead, aLine[3:].strip(), [], sAlign | self.A_CENTRE self.T_TITLE, nHead, aLine[3:].strip(), [], self.A_PBB | self.A_CENTRE
)) ))
if self._keepMarkdown: if self._keepMarkdown:
tmpMarkdown.append("%s\n" % aLine) tmpMarkdown.append("%s\n" % aLine)
elif aLine[:4] == "##! ": elif aLine[:4] == "##! ":
nHead += 1 nHead += 1
if self._isNovel: # If we're not in a novel section, we just treat this as a regular H2
tStyle = self.T_UNNUM tStyle = self.T_UNNUM if self._isNovel else self.T_HEAD2
sAlign |= self.A_PBB
else:
tStyle = self.T_HEAD2
self._tokens.append(( self._tokens.append((
tStyle, nHead, aLine[4:].strip(), [], sAlign tStyle, nHead, aLine[4:].strip(), [], self.A_NONE
)) ))
if self._keepMarkdown: if self._keepMarkdown:
tmpMarkdown.append("%s\n" % aLine) tmpMarkdown.append("%s\n" % aLine)
@@ -622,7 +640,8 @@ class Tokenizer(ABC):
# If we have content, turn off the first page flag # If we have content, turn off the first page flag
if self._isFirst and self._tokens: if self._isFirst and self._tokens:
self._isFirst = False self._isFirst = False # First document has been processed
self._noBreak = True # Check again after headers are processed
# Make sure the token array doesn't start with a page break # Make sure the token array doesn't start with a page break
# on the very first page, adding a blank first page. # on the very first page, adding a blank first page.
@@ -686,7 +705,7 @@ class Tokenizer(ABC):
tTemp = self._hFormatter.apply(self._fmtTitle, token[2], token[1]) tTemp = self._hFormatter.apply(self._fmtTitle, token[2], token[1])
self._tokens[n] = ( self._tokens[n] = (
token[0], token[1], tTemp, [], token[4] token[0], token[1], tTemp, [], self._titleStyle
) )
# Set scene variables # Set scene variables
@@ -704,7 +723,7 @@ class Tokenizer(ABC):
# Format the chapter header # Format the chapter header
self._tokens[n] = ( self._tokens[n] = (
token[0], token[1], tTemp, [], token[4] token[0], token[1], tTemp, [], self._chapterStyle
) )
# Set scene variables # Set scene variables
@@ -729,11 +748,11 @@ class Tokenizer(ABC):
self._tokens[n] = ( self._tokens[n] = (
self.T_EMPTY if self._skipSeparator else self.T_SEP, token[1], self.T_EMPTY if self._skipSeparator else self.T_SEP, token[1],
"" if self._skipSeparator else tTemp, [], "" if self._skipSeparator else tTemp, [],
self.A_NONE if self._skipSeparator else (token[4] | self.A_CENTRE) self.A_NONE if self._skipSeparator else self.A_CENTRE
) )
else: else:
self._tokens[n] = ( self._tokens[n] = (
token[0], token[1], tTemp, [], token[4] token[0], token[1], tTemp, [], self._sceneStyle
) )
self._skipSeparator = False self._skipSeparator = False
@@ -758,6 +777,15 @@ class Tokenizer(ABC):
token[0], token[1], tTemp, [], token[4] token[0], token[1], tTemp, [], token[4]
) )
if n == 0 and self._noBreak:
# Make sure again that the token array doesn't start with a page break
self._noBreak = False
if self._tokens[0][4] & self.A_PBB:
token = self._tokens[0]
self._tokens[0] = (
token[0], token[1], token[2], token[3], token[4] & ~self.A_PBB
)
return True return True
def countStats(self) -> dict[str, int]: def countStats(self) -> dict[str, int]:
+8 -1
View File
@@ -49,6 +49,7 @@ class ToMarkdown(Tokenizer):
super().__init__(project) super().__init__(project)
self._genMode = self.M_STD self._genMode = self.M_STD
self._fullMD: list[str] = [] self._fullMD: list[str] = []
self._preserveBreaks = True
return return
## ##
@@ -74,6 +75,11 @@ class ToMarkdown(Tokenizer):
self._genMode = self.M_EXT self._genMode = self.M_EXT
return return
def setPreserveBreaks(self, state: bool) -> None:
"""Preserve line breaks in paragraphs."""
self._preserveBreaks = state
return
## ##
# Class Methods # Class Methods
## ##
@@ -125,12 +131,13 @@ class ToMarkdown(Tokenizer):
para = [] para = []
lines = [] lines = []
lineSep = " \n" if self._preserveBreaks else " "
for tType, _, tText, tFormat, tStyle in self._tokens: for tType, _, tText, tFormat, tStyle in self._tokens:
if tType == self.T_EMPTY: if tType == self.T_EMPTY:
if len(para) > 0: if len(para) > 0:
tTemp = (" \n".join(para)).rstrip(" ") tTemp = (lineSep.join(para)).rstrip(" ")
lines.append(f"{tTemp}\n\n") lines.append(f"{tTemp}\n\n")
para = [] para = []
+2 -1
View File
@@ -337,7 +337,8 @@ class GuiManuscript(QDialog):
if build is None: if build is None:
return return
docBuild = NWBuildDocument(SHARED.project, build, doCount=True) docBuild = NWBuildDocument(SHARED.project, build)
docBuild.setPreviewMode(True)
docBuild.queueAll() docBuild.queueAll()
self.docPreview.beginNewBuild(len(docBuild)) self.docPreview.beginNewBuild(len(docBuild))
+139 -21
View File
@@ -37,7 +37,7 @@ from PyQt5.QtWidgets import (
) )
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
from novelwriter.constants import nwHeadFmt, nwLabels, trConst from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, trConst
from novelwriter.core.buildsettings import BuildSettings, FilterMode from novelwriter.core.buildsettings import BuildSettings, FilterMode
from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.switch import NSwitch
from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NSpinBox from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NSpinBox
@@ -593,6 +593,7 @@ class _HeadingsTab(NScrollablePage):
self._editing = 0 self._editing = 0
iPx = SHARED.theme.baseIconSize iPx = SHARED.theme.baseIconSize
sSp = CONFIG.pxInt(16)
vSp = CONFIG.pxInt(12) vSp = CONFIG.pxInt(12)
bSp = CONFIG.pxInt(6) bSp = CONFIG.pxInt(6)
@@ -614,8 +615,8 @@ class _HeadingsTab(NScrollablePage):
wrapTitle.addWidget(self.btnTitle) wrapTitle.addWidget(self.btnTitle)
wrapTitle.setSpacing(bSp) wrapTitle.setSpacing(bSp)
self.formatBox.addWidget(self.lblTitle, 0, 0, Qt.AlignLeft) self.formatBox.addWidget(self.lblTitle, 0, 0)
self.formatBox.addLayout(wrapTitle, 0, 1, Qt.AlignLeft) self.formatBox.addLayout(wrapTitle, 0, 1)
# Chapter Heading # Chapter Heading
self.lblChapter = QLabel(self._build.getLabel("headings.fmtChapter")) self.lblChapter = QLabel(self._build.getLabel("headings.fmtChapter"))
@@ -630,8 +631,8 @@ class _HeadingsTab(NScrollablePage):
wrapChapter.addWidget(self.btnChapter) wrapChapter.addWidget(self.btnChapter)
wrapChapter.setSpacing(bSp) wrapChapter.setSpacing(bSp)
self.formatBox.addWidget(self.lblChapter, 1, 0, Qt.AlignLeft) self.formatBox.addWidget(self.lblChapter, 1, 0)
self.formatBox.addLayout(wrapChapter, 1, 1, Qt.AlignLeft) self.formatBox.addLayout(wrapChapter, 1, 1)
# Unnumbered Chapter Heading # Unnumbered Chapter Heading
self.lblUnnumbered = QLabel(self._build.getLabel("headings.fmtUnnumbered")) self.lblUnnumbered = QLabel(self._build.getLabel("headings.fmtUnnumbered"))
@@ -646,8 +647,8 @@ class _HeadingsTab(NScrollablePage):
wrapUnnumbered.addWidget(self.btnUnnumbered) wrapUnnumbered.addWidget(self.btnUnnumbered)
wrapUnnumbered.setSpacing(bSp) wrapUnnumbered.setSpacing(bSp)
self.formatBox.addWidget(self.lblUnnumbered, 2, 0, Qt.AlignLeft) self.formatBox.addWidget(self.lblUnnumbered, 2, 0)
self.formatBox.addLayout(wrapUnnumbered, 2, 1, Qt.AlignLeft) self.formatBox.addLayout(wrapUnnumbered, 2, 1)
# Scene Heading # Scene Heading
sceneHideTip = self._build.getLabel("headings.hideScene") sceneHideTip = self._build.getLabel("headings.hideScene")
@@ -672,9 +673,9 @@ class _HeadingsTab(NScrollablePage):
wrapSceneHide.addWidget(self.swtScene) wrapSceneHide.addWidget(self.swtScene)
wrapSceneHide.setSpacing(bSp) wrapSceneHide.setSpacing(bSp)
self.formatBox.addWidget(self.lblScene, 3, 0, Qt.AlignLeft) self.formatBox.addWidget(self.lblScene, 3, 0)
self.formatBox.addLayout(wrapScene, 3, 1, Qt.AlignLeft) self.formatBox.addLayout(wrapScene, 3, 1)
self.formatBox.addLayout(wrapSceneHide, 3, 2, Qt.AlignLeft) self.formatBox.addLayout(wrapSceneHide, 3, 2)
# Section Heading # Section Heading
sectionHideTip = self._build.getLabel("headings.hideSection") sectionHideTip = self._build.getLabel("headings.hideSection")
@@ -699,16 +700,16 @@ class _HeadingsTab(NScrollablePage):
wrapSectionHide.addWidget(self.swtSection) wrapSectionHide.addWidget(self.swtSection)
wrapSectionHide.setSpacing(bSp) wrapSectionHide.setSpacing(bSp)
self.formatBox.addWidget(self.lblSection, 4, 0, Qt.AlignLeft) self.formatBox.addWidget(self.lblSection, 4, 0)
self.formatBox.addLayout(wrapSection, 4, 1, Qt.AlignLeft) self.formatBox.addLayout(wrapSection, 4, 1)
self.formatBox.addLayout(wrapSectionHide, 4, 2, Qt.AlignLeft) self.formatBox.addLayout(wrapSectionHide, 4, 2)
# Edit Form # Edit Form
# ========= # =========
self.lblEditForm = QLabel(self.tr("Editing: {0}").format(self.tr("None"))) self.lblEditForm = QLabel(self.tr("Editing: {0}").format(self.tr("None")))
self.editTextBox = QPlainTextEdit() self.editTextBox = QPlainTextEdit(self)
self.editTextBox.setFixedHeight(5*iPx) self.editTextBox.setFixedHeight(5*iPx)
self.editTextBox.setEnabled(False) self.editTextBox.setEnabled(False)
@@ -735,10 +736,10 @@ class _HeadingsTab(NScrollablePage):
self.aInsCharPOV.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_POV)) self.aInsCharPOV.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_POV))
self.aInsCharFocus.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_FOCUS)) self.aInsCharFocus.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_FOCUS))
self.btnInsert = QPushButton(self.tr("Insert")) self.btnInsert = QPushButton(self.tr("Insert"), self)
self.btnInsert.setMenu(self.menuInsert) self.btnInsert.setMenu(self.menuInsert)
self.btnApply = QPushButton(self.tr("Apply")) self.btnApply = QPushButton(self.tr("Apply"), self)
self.btnApply.clicked.connect(self._saveFormat) self.btnApply.clicked.connect(self._saveFormat)
self.formButtonBox = QHBoxLayout() self.formButtonBox = QHBoxLayout()
@@ -751,13 +752,72 @@ class _HeadingsTab(NScrollablePage):
self.editFormBox.addWidget(self.editTextBox) self.editFormBox.addWidget(self.editTextBox)
self.editFormBox.addLayout(self.formButtonBox) self.editFormBox.addLayout(self.formButtonBox)
# Layout Matrix
# =============
self.layoutMatrix = QGridLayout()
self.layoutMatrix.setVerticalSpacing(vSp)
self.layoutMatrix.setHorizontalSpacing(vSp)
# Heading
self.layoutHeading = QLabel("<b>{0}</b>".format(self.tr("Additional Styling")), self)
self.layoutMatrix.addWidget(self.layoutHeading, 0, 0, 1, 5)
# Title Layout
self.mtxTitle = QLabel(self._build.getLabel("headings.fmtTitle"))
self.centerTitle = NSwitch(self, height=iPx)
self.breakTitle = NSwitch(self, height=iPx)
lblCenterT = QLabel(self.tr("Centre"))
lblCenterT.setIndent(sSp)
lblBreakT = QLabel(self.tr("Page Break"))
lblBreakT.setIndent(sSp)
self.layoutMatrix.addWidget(self.mtxTitle, 1, 0)
self.layoutMatrix.addWidget(lblCenterT, 1, 1)
self.layoutMatrix.addWidget(self.centerTitle, 1, 2)
self.layoutMatrix.addWidget(lblBreakT, 1, 3)
self.layoutMatrix.addWidget(self.breakTitle, 1, 4)
# Chapter Layout
self.mtxChapter = QLabel(self._build.getLabel("headings.fmtChapter"))
self.centerChapter = NSwitch(self, height=iPx)
self.breakChapter = NSwitch(self, height=iPx)
lblCenterC = QLabel(self.tr("Centre"))
lblCenterC.setIndent(sSp)
lblBreakC = QLabel(self.tr("Page Break"))
lblBreakC.setIndent(sSp)
self.layoutMatrix.addWidget(self.mtxChapter, 2, 0)
self.layoutMatrix.addWidget(lblCenterC, 2, 1)
self.layoutMatrix.addWidget(self.centerChapter, 2, 2)
self.layoutMatrix.addWidget(lblBreakC, 2, 3)
self.layoutMatrix.addWidget(self.breakChapter, 2, 4)
# Scene Layout
self.mtxScene = QLabel(self._build.getLabel("headings.fmtScene"))
self.centerScene = NSwitch(self, height=iPx)
self.breakScene = NSwitch(self, height=iPx)
lblCenterS = QLabel(self.tr("Centre"))
lblCenterS.setIndent(sSp)
lblBreakS = QLabel(self.tr("Page Break"))
lblBreakS.setIndent(sSp)
self.layoutMatrix.addWidget(self.mtxScene, 3, 0)
self.layoutMatrix.addWidget(lblCenterS, 3, 1)
self.layoutMatrix.addWidget(self.centerScene, 3, 2)
self.layoutMatrix.addWidget(lblBreakS, 3, 3)
self.layoutMatrix.addWidget(self.breakScene, 3, 4)
self.layoutMatrix.setColumnStretch(5, 1)
# Assemble # Assemble
# ======== # ========
self.outerBox = QVBoxLayout() self.outerBox = QVBoxLayout()
self.outerBox.addLayout(self.formatBox) self.outerBox.addLayout(self.formatBox)
self.outerBox.addSpacing(CONFIG.pxInt(16)) self.outerBox.addSpacing(sSp)
self.outerBox.addLayout(self.editFormBox) self.outerBox.addLayout(self.editFormBox)
self.outerBox.addSpacing(sSp)
self.outerBox.addLayout(self.layoutMatrix)
self.outerBox.addStretch(1) self.outerBox.addStretch(1)
self.setCentralLayout(self.outerBox) self.setCentralLayout(self.outerBox)
@@ -773,12 +833,24 @@ class _HeadingsTab(NScrollablePage):
self.fmtSection.setText(self._build.getStr("headings.fmtSection")) self.fmtSection.setText(self._build.getStr("headings.fmtSection"))
self.swtScene.setChecked(self._build.getBool("headings.hideScene")) self.swtScene.setChecked(self._build.getBool("headings.hideScene"))
self.swtSection.setChecked(self._build.getBool("headings.hideSection")) self.swtSection.setChecked(self._build.getBool("headings.hideSection"))
self.centerTitle.setChecked(self._build.getBool("headings.centerTitle"))
self.centerChapter.setChecked(self._build.getBool("headings.centerChapter"))
self.centerScene.setChecked(self._build.getBool("headings.centerScene"))
self.breakTitle.setChecked(self._build.getBool("headings.breakTitle"))
self.breakChapter.setChecked(self._build.getBool("headings.breakChapter"))
self.breakScene.setChecked(self._build.getBool("headings.breakScene"))
return return
def saveContent(self) -> None: def saveContent(self) -> None:
"""Save choices back into build object.""" """Save choices back into build object."""
self._build.setValue("headings.hideScene", self.swtScene.isChecked()) self._build.setValue("headings.hideScene", self.swtScene.isChecked())
self._build.setValue("headings.hideSection", self.swtSection.isChecked()) self._build.setValue("headings.hideSection", self.swtSection.isChecked())
self._build.setValue("headings.centerTitle", self.centerTitle.isChecked())
self._build.setValue("headings.centerChapter", self.centerChapter.isChecked())
self._build.setValue("headings.centerScene", self.centerScene.isChecked())
self._build.setValue("headings.breakTitle", self.breakTitle.isChecked())
self._build.setValue("headings.breakChapter", self.breakChapter.isChecked())
self._build.setValue("headings.breakScene", self.breakScene.isChecked())
return return
## ##
@@ -894,16 +966,32 @@ class _ContentTab(NScrollableForm):
iPx = SHARED.theme.baseIconSize iPx = SHARED.theme.baseIconSize
# Text Content # Text Content
self.incBodyText = NSwitch(self, height=iPx)
self.incSynopsis = NSwitch(self, height=iPx) self.incSynopsis = NSwitch(self, height=iPx)
self.incComments = NSwitch(self, height=iPx) self.incComments = NSwitch(self, height=iPx)
self.incKeywords = NSwitch(self, height=iPx) self.incKeywords = NSwitch(self, height=iPx)
self.incBodyText = NSwitch(self, height=iPx)
self.ignoredKeywords = QLineEdit(self)
self.mnKeywords = QMenu(self)
for keyword in nwKeyWords.VALID_KEYS:
self.mnKeywords.addAction(
trConst(nwLabels.KEY_NAME[keyword]),
lambda keyword=keyword: self._updateIgnoredKeywords(keyword)
)
self.ignoredKeywordsButton = QToolButton(self)
self.ignoredKeywordsButton.setIcon(SHARED.theme.getIcon("add"))
self.ignoredKeywordsButton.setMenu(self.mnKeywords)
self.ignoredKeywordsButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
self.addGroupLabel(self._build.getLabel("text.grpContent")) self.addGroupLabel(self._build.getLabel("text.grpContent"))
self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText)
self.addRow(self._build.getLabel("text.includeSynopsis"), self.incSynopsis) self.addRow(self._build.getLabel("text.includeSynopsis"), self.incSynopsis)
self.addRow(self._build.getLabel("text.includeComments"), self.incComments) self.addRow(self._build.getLabel("text.includeComments"), self.incComments)
self.addRow(self._build.getLabel("text.includeKeywords"), self.incKeywords) self.addRow(self._build.getLabel("text.includeKeywords"), self.incKeywords)
self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText) self.addRow(self._build.getLabel("text.ignoredKeywords"), self.ignoredKeywords,
button=self.ignoredKeywordsButton, stretch=(1, 1))
# Insert Content # Insert Content
self.addNoteHead = NSwitch(self, height=iPx) self.addNoteHead = NSwitch(self, height=iPx)
@@ -918,22 +1006,39 @@ class _ContentTab(NScrollableForm):
def loadContent(self) -> None: def loadContent(self) -> None:
"""Populate the widgets.""" """Populate the widgets."""
self.incBodyText.setChecked(self._build.getBool("text.includeBodyText"))
self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis")) self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis"))
self.incComments.setChecked(self._build.getBool("text.includeComments")) self.incComments.setChecked(self._build.getBool("text.includeComments"))
self.incKeywords.setChecked(self._build.getBool("text.includeKeywords")) self.incKeywords.setChecked(self._build.getBool("text.includeKeywords"))
self.incBodyText.setChecked(self._build.getBool("text.includeBodyText")) self.ignoredKeywords.setText(self._build.getStr("text.ignoredKeywords"))
self.addNoteHead.setChecked(self._build.getBool("text.addNoteHeadings")) self.addNoteHead.setChecked(self._build.getBool("text.addNoteHeadings"))
self._updateIgnoredKeywords()
return return
def saveContent(self) -> None: def saveContent(self) -> None:
"""Save choices back into build object.""" """Save choices back into build object."""
self._updateIgnoredKeywords()
self._build.setValue("text.includeBodyText", self.incBodyText.isChecked())
self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked()) self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked())
self._build.setValue("text.includeComments", self.incComments.isChecked()) self._build.setValue("text.includeComments", self.incComments.isChecked())
self._build.setValue("text.includeKeywords", self.incKeywords.isChecked()) self._build.setValue("text.includeKeywords", self.incKeywords.isChecked())
self._build.setValue("text.includeBodyText", self.incBodyText.isChecked()) self._build.setValue("text.ignoredKeywords", self.ignoredKeywords.text())
self._build.setValue("text.addNoteHeadings", self.addNoteHead.isChecked()) self._build.setValue("text.addNoteHeadings", self.addNoteHead.isChecked())
return return
##
# Internal Functions
##
def _updateIgnoredKeywords(self, keyword: str | None = None) -> None:
"""Update the ignored keywords list."""
current = [x.lower().strip() for x in self.ignoredKeywords.text().split(",")]
if keyword:
current.append(keyword)
verified = set(x for x in current if x in nwKeyWords.VALID_KEYS)
self.ignoredKeywords.setText(", ".join(verified))
return
# END Class _ContentTab # END Class _ContentTab
@@ -1245,6 +1350,15 @@ class _OutputTab(NScrollableForm):
self.htmlAddStyles = NSwitch(self, height=iPx) self.htmlAddStyles = NSwitch(self, height=iPx)
self.addRow(self._build.getLabel("html.addStyles"), self.htmlAddStyles) self.addRow(self._build.getLabel("html.addStyles"), self.htmlAddStyles)
self.htmlPreserveTabs = NSwitch(self, height=iPx)
self.addRow(self._build.getLabel("html.preserveTabs"), self.htmlPreserveTabs)
# Markdown Document
self.addGroupLabel(self._build.getLabel("md"))
self.mdPreserveBreaks = NSwitch(self, height=iPx)
self.addRow(self._build.getLabel("md.preserveBreaks"), self.mdPreserveBreaks)
# Finalise # Finalise
self.finalise() self.finalise()
@@ -1256,6 +1370,8 @@ class _OutputTab(NScrollableForm):
self.odtPageHeader.setText(self._build.getStr("odt.pageHeader")) self.odtPageHeader.setText(self._build.getStr("odt.pageHeader"))
self.odtPageCountOffset.setValue(self._build.getInt("odt.pageCountOffset")) self.odtPageCountOffset.setValue(self._build.getInt("odt.pageCountOffset"))
self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles")) self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles"))
self.htmlPreserveTabs.setChecked(self._build.getBool("html.preserveTabs"))
self.mdPreserveBreaks.setChecked(self._build.getBool("md.preserveBreaks"))
return return
def saveContent(self) -> None: def saveContent(self) -> None:
@@ -1264,6 +1380,8 @@ class _OutputTab(NScrollableForm):
self._build.setValue("odt.pageHeader", self.odtPageHeader.text()) self._build.setValue("odt.pageHeader", self.odtPageHeader.text())
self._build.setValue("odt.pageCountOffset", self.odtPageCountOffset.value()) self._build.setValue("odt.pageCountOffset", self.odtPageCountOffset.value())
self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked()) self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked())
self._build.setValue("html.preserveTabs", self.htmlPreserveTabs.isChecked())
self._build.setValue("md.preserveBreaks", self.mdPreserveBreaks.isChecked())
return return
## ##
+2 -1
View File
@@ -83,7 +83,8 @@ def testCoreDocBuild_OpenDocument(monkeypatch, mockGUI, prjLipsum, fncPath, tstP
build = BuildSettings() build = BuildSettings()
build.unpack(BUILD_CONF) build.unpack(BUILD_CONF)
docBuild = NWBuildDocument(project, build, doCount=True) docBuild = NWBuildDocument(project, build)
docBuild.setCountEnabled(True)
docBuild.queueAll() docBuild.queueAll()
assert len(docBuild) == 21 assert len(docBuild) == 21
+22 -2
View File
@@ -44,6 +44,7 @@ def testCoreToHtml_ConvertHeaders(mockGUI):
# Header 1 # Header 1
html._text = "# Partition\n" html._text = "# Partition\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == ( assert html.result == (
"<h1 class='title' style='text-align: center;'>Partition</h1>\n" "<h1 class='title' style='text-align: center;'>Partition</h1>\n"
@@ -52,6 +53,7 @@ def testCoreToHtml_ConvertHeaders(mockGUI):
# Header 2 # Header 2
html._text = "## Chapter Title\n" html._text = "## Chapter Title\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == ( assert html.result == (
"<h1 style='page-break-before: always;'>Chapter Title</h1>\n" "<h1 style='page-break-before: always;'>Chapter Title</h1>\n"
@@ -60,26 +62,30 @@ def testCoreToHtml_ConvertHeaders(mockGUI):
# Header 3 # Header 3
html._text = "### Scene Title\n" html._text = "### Scene Title\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == "<h2>Scene Title</h2>\n" assert html.result == "<h2>Scene Title</h2>\n"
# Header 4 # Header 4
html._text = "#### Section Title\n" html._text = "#### Section Title\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == "<h3>Section Title</h3>\n" assert html.result == "<h3>Section Title</h3>\n"
# Title # Title
html._text = "#! Title\n" html._text = "#! Title\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == ( assert html.result == (
"<h1 class='title' style='text-align: center;'>Title</h1>\n" "<h1 class='title' style='text-align: center; page-break-before: always;'>Title</h1>\n"
) )
# Unnumbered # Unnumbered
html._text = "##! Prologue\n" html._text = "##! Prologue\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == "<h1 style='page-break-before: always;'>Prologue</h1>\n" assert html.result == "<h1 style='page-break-before: always;'>Prologue</h1>\n"
@@ -94,38 +100,45 @@ def testCoreToHtml_ConvertHeaders(mockGUI):
# Header 1 # Header 1
html._text = "# Heading One\n" html._text = "# Heading One\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == "<h1><a name='T0001'></a>Heading One</h1>\n" assert html.result == "<h1><a name='T0001'></a>Heading One</h1>\n"
# Header 2 # Header 2
html._text = "## Heading Two\n" html._text = "## Heading Two\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == "<h2><a name='T0001'></a>Heading Two</h2>\n" assert html.result == "<h2><a name='T0001'></a>Heading Two</h2>\n"
# Header 3 # Header 3
html._text = "### Heading Three\n" html._text = "### Heading Three\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == "<h3><a name='T0001'></a>Heading Three</h3>\n" assert html.result == "<h3><a name='T0001'></a>Heading Three</h3>\n"
# Header 4 # Header 4
html._text = "#### Heading Four\n" html._text = "#### Heading Four\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == "<h4><a name='T0001'></a>Heading Four</h4>\n" assert html.result == "<h4><a name='T0001'></a>Heading Four</h4>\n"
# Title # Title
html._text = "#! Heading One\n" html._text = "#! Heading One\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == ( assert html.result == (
"<h1 style='text-align: center;'><a name='T0001'></a>Heading One</h1>\n" "<h1 class='title' style='text-align: center; page-break-before: always;'>"
"<a name='T0001'></a>Heading One</h1>\n"
) )
# Unnumbered # Unnumbered
html._text = "##! Heading Two\n" html._text = "##! Heading Two\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == "<h2><a name='T0001'></a>Heading Two</h2>\n" assert html.result == "<h2><a name='T0001'></a>Heading Two</h2>\n"
@@ -227,9 +240,12 @@ def testCoreToHtml_ConvertParagraphs(mockGUI):
) )
# Multiple Keywords # Multiple Keywords
html._isFirst = False
html._noBreak = False
html.setKeywords(True) html.setKeywords(True)
html._text = "## Chapter\n\n@pov: Bod\n@plot: Main\n@location: Europe\n\n" html._text = "## Chapter\n\n@pov: Bod\n@plot: Main\n@location: Europe\n\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == ( assert html.result == (
"<h1 style='page-break-before: always;'>Chapter</h1>\n" "<h1 style='page-break-before: always;'>Chapter</h1>\n"
@@ -457,8 +473,11 @@ def testCoreToHtml_SpecialCases(mockGUI):
"</p>\n" "</p>\n"
) )
html._isFirst = False
html._noBreak = False
html._text = "## Heading <1>\n" html._text = "## Heading <1>\n"
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == ( assert html.result == (
"<h1 style='page-break-before: always;'>Heading &lt;1&gt;</h1>\n" "<h1 style='page-break-before: always;'>Heading &lt;1&gt;</h1>\n"
@@ -532,6 +551,7 @@ def testCoreToHtml_Complex(mockGUI, fncPath):
html._text = docText[i] html._text = docText[i]
html.doPreProcessing() html.doPreProcessing()
html.tokenizeText() html.tokenizeText()
html.doHeaders()
html.doConvert() html.doConvert()
assert html.result == resText[i] assert html.result == resText[i]
+312 -3
View File
@@ -261,7 +261,7 @@ def testCoreToken_HeaderFormat(mockGUI):
tokens.tokenizeText() tokens.tokenizeText()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Note Title", [], Tokenizer.A_CENTRE), (Tokenizer.T_TITLE, 1, "Note Title", [], Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
] ]
assert tokens.allMarkdown[-1] == "#! Note Title\n\n" assert tokens.allMarkdown[-1] == "#! Note Title\n\n"
@@ -276,6 +276,7 @@ def testCoreToken_HeaderFormat(mockGUI):
tokens._text = "# Novel Title\n" tokens._text = "# Novel Title\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Novel Title", [], Tokenizer.A_CENTRE), (Tokenizer.T_HEAD1, 1, "Novel Title", [], Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -289,6 +290,7 @@ def testCoreToken_HeaderFormat(mockGUI):
tokens._text = "# Note Title\n" tokens._text = "# Note Title\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Note Title", [], Tokenizer.A_NONE), (Tokenizer.T_HEAD1, 1, "Note Title", [], Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -301,9 +303,11 @@ def testCoreToken_HeaderFormat(mockGUI):
# Story File # Story File
tokens._isNovel = True tokens._isNovel = True
tokens._isNote = False tokens._isNote = False
tokens._noBreak = False
tokens._text = "## Chapter One\n" tokens._text = "## Chapter One\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD2, 1, "Chapter One", [], Tokenizer.A_PBB), (Tokenizer.T_HEAD2, 1, "Chapter One", [], Tokenizer.A_PBB),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -316,6 +320,7 @@ def testCoreToken_HeaderFormat(mockGUI):
tokens._text = "## Heading 2\n" tokens._text = "## Heading 2\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD2, 1, "Heading 2", [], Tokenizer.A_NONE), (Tokenizer.T_HEAD2, 1, "Heading 2", [], Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -331,6 +336,7 @@ def testCoreToken_HeaderFormat(mockGUI):
tokens._text = "### Scene One\n" tokens._text = "### Scene One\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD3, 1, "Scene One", [], Tokenizer.A_NONE), (Tokenizer.T_HEAD3, 1, "Scene One", [], Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -343,6 +349,7 @@ def testCoreToken_HeaderFormat(mockGUI):
tokens._text = "### Heading 3\n" tokens._text = "### Heading 3\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD3, 1, "Heading 3", [], Tokenizer.A_NONE), (Tokenizer.T_HEAD3, 1, "Heading 3", [], Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -358,6 +365,7 @@ def testCoreToken_HeaderFormat(mockGUI):
tokens._text = "#### A Section\n" tokens._text = "#### A Section\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD4, 1, "A Section", [], Tokenizer.A_NONE), (Tokenizer.T_HEAD4, 1, "A Section", [], Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -370,6 +378,7 @@ def testCoreToken_HeaderFormat(mockGUI):
tokens._text = "#### Heading 4\n" tokens._text = "#### Heading 4\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD4, 1, "Heading 4", [], Tokenizer.A_NONE), (Tokenizer.T_HEAD4, 1, "Heading 4", [], Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -382,11 +391,13 @@ def testCoreToken_HeaderFormat(mockGUI):
# Story File # Story File
tokens._isNovel = True tokens._isNovel = True
tokens._isNote = False tokens._isNote = False
tokens._isFirst = False
tokens._text = "#! Title\n" tokens._text = "#! Title\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_TITLE, 1, "Title", [], Tokenizer.A_CENTRE), (Tokenizer.T_TITLE, 1, "Title", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
] ]
assert tokens.allMarkdown[-1] == "#! Title\n\n" assert tokens.allMarkdown[-1] == "#! Title\n\n"
@@ -394,11 +405,13 @@ def testCoreToken_HeaderFormat(mockGUI):
# Note File # Note File
tokens._isNovel = False tokens._isNovel = False
tokens._isNote = True tokens._isNote = True
tokens._isFirst = False
tokens._text = "#! Title\n" tokens._text = "#! Title\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Title", [], Tokenizer.A_CENTRE), (Tokenizer.T_TITLE, 1, "Title", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
] ]
assert tokens.allMarkdown[-1] == "#! Title\n\n" assert tokens.allMarkdown[-1] == "#! Title\n\n"
@@ -412,6 +425,7 @@ def testCoreToken_HeaderFormat(mockGUI):
tokens._text = "##! Prologue\n" tokens._text = "##! Prologue\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_UNNUM, 1, "Prologue", [], Tokenizer.A_PBB), (Tokenizer.T_UNNUM, 1, "Prologue", [], Tokenizer.A_PBB),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -424,6 +438,7 @@ def testCoreToken_HeaderFormat(mockGUI):
tokens._text = "##! Prologue\n" tokens._text = "##! Prologue\n"
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD2, 1, "Prologue", [], Tokenizer.A_NONE), (Tokenizer.T_HEAD2, 1, "Prologue", [], Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -433,6 +448,280 @@ def testCoreToken_HeaderFormat(mockGUI):
# END Test testCoreToken_HeaderFormat # END Test testCoreToken_HeaderFormat
@pytest.mark.core
def testCoreToken_HeaderStyle(mockGUI):
"""Test the styling of headers in the Tokenizer class."""
project = NWProject()
tokens = BareTokenizer(project)
def processStyle(text: str, first: bool) -> int:
tokens._text = text
tokens._isFirst = first
tokens._noBreak = first
tokens.tokenizeText()
tokens.doHeaders()
return tokens._tokens[0][4]
# No Styles
# =========
tokens.setTitleStyle(False, False)
tokens.setChapterStyle(False, False)
tokens.setSceneStyle(False, False)
assert tokens._titleStyle == Tokenizer.A_NONE
assert tokens._chapterStyle == Tokenizer.A_NONE
assert tokens._sceneStyle == Tokenizer.A_NONE
# Novel Docs
tokens._isNovel = True
tokens._isNote = False
# First Document is False
assert processStyle("# Title\n", False) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", False) == Tokenizer.A_NONE
assert processStyle("### Scene\n", False) == Tokenizer.A_NONE
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_NONE
# First Document is True
assert processStyle("# Title\n", True) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", True) == Tokenizer.A_NONE
assert processStyle("### Scene\n", True) == Tokenizer.A_NONE
assert processStyle("#### Section\n", True) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", True) == Tokenizer.A_CENTRE
assert processStyle("##! Prologue\n", True) == Tokenizer.A_NONE
# Note Docs
tokens._isNovel = False
tokens._isNote = True
# First Document is False
assert processStyle("# Title\n", False) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", False) == Tokenizer.A_NONE
assert processStyle("### Scene\n", False) == Tokenizer.A_NONE
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_NONE
# First Document is True
assert processStyle("# Title\n", True) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", True) == Tokenizer.A_NONE
assert processStyle("### Scene\n", True) == Tokenizer.A_NONE
assert processStyle("#### Section\n", True) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", True) == Tokenizer.A_CENTRE
assert processStyle("##! Prologue\n", True) == Tokenizer.A_NONE
# Center Headers
# ==============
tokens.setTitleStyle(True, False)
tokens.setChapterStyle(True, False)
tokens.setSceneStyle(True, False)
assert tokens._titleStyle == Tokenizer.A_CENTRE
assert tokens._chapterStyle == Tokenizer.A_CENTRE
assert tokens._sceneStyle == Tokenizer.A_CENTRE
# Novel Docs
tokens._isNovel = True
tokens._isNote = False
# First Document is False
assert processStyle("# Title\n", False) == Tokenizer.A_CENTRE
assert processStyle("## Chapter\n", False) == Tokenizer.A_CENTRE
assert processStyle("### Scene\n", False) == Tokenizer.A_CENTRE
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_CENTRE
# First Document is True
assert processStyle("# Title\n", True) == Tokenizer.A_CENTRE
assert processStyle("## Chapter\n", True) == Tokenizer.A_CENTRE
assert processStyle("### Scene\n", True) == Tokenizer.A_CENTRE
assert processStyle("#### Section\n", True) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", True) == Tokenizer.A_CENTRE
assert processStyle("##! Prologue\n", True) == Tokenizer.A_CENTRE
# Note Docs
tokens._isNovel = False
tokens._isNote = True
# First Document is False
assert processStyle("# Title\n", False) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", False) == Tokenizer.A_NONE
assert processStyle("### Scene\n", False) == Tokenizer.A_NONE
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_NONE
# First Document is True
assert processStyle("# Title\n", True) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", True) == Tokenizer.A_NONE
assert processStyle("### Scene\n", True) == Tokenizer.A_NONE
assert processStyle("#### Section\n", True) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", True) == Tokenizer.A_CENTRE
assert processStyle("##! Prologue\n", True) == Tokenizer.A_NONE
# Page Break Headers
# ==================
tokens.setTitleStyle(False, True)
tokens.setChapterStyle(False, True)
tokens.setSceneStyle(False, True)
assert tokens._titleStyle == Tokenizer.A_PBB
assert tokens._chapterStyle == Tokenizer.A_PBB
assert tokens._sceneStyle == Tokenizer.A_PBB
# Novel Docs
tokens._isNovel = True
tokens._isNote = False
# First Document is False
assert processStyle("# Title\n", False) == Tokenizer.A_PBB
assert processStyle("## Chapter\n", False) == Tokenizer.A_PBB
assert processStyle("### Scene\n", False) == Tokenizer.A_PBB
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_PBB
# First Document is True
assert processStyle("# Title\n", True) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", True) == Tokenizer.A_NONE
assert processStyle("### Scene\n", True) == Tokenizer.A_NONE
assert processStyle("#### Section\n", True) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", True) == Tokenizer.A_CENTRE
assert processStyle("##! Prologue\n", True) == Tokenizer.A_NONE
# Note Docs
tokens._isNovel = False
tokens._isNote = True
# First Document is False
assert processStyle("# Title\n", False) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", False) == Tokenizer.A_NONE
assert processStyle("### Scene\n", False) == Tokenizer.A_NONE
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_NONE
# First Document is True
assert processStyle("# Title\n", True) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", True) == Tokenizer.A_NONE
assert processStyle("### Scene\n", True) == Tokenizer.A_NONE
assert processStyle("#### Section\n", True) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", True) == Tokenizer.A_CENTRE
assert processStyle("##! Prologue\n", True) == Tokenizer.A_NONE
# Page Break and Centre Headers
# =============================
tokens.setTitleStyle(True, True)
tokens.setChapterStyle(True, True)
tokens.setSceneStyle(True, True)
assert tokens._titleStyle == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert tokens._chapterStyle == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert tokens._sceneStyle == Tokenizer.A_CENTRE | Tokenizer.A_PBB
# Novel Docs
tokens._isNovel = True
tokens._isNote = False
# First Document is False
assert processStyle("# Title\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("## Chapter\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("### Scene\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
# First Document is True
assert processStyle("# Title\n", True) == Tokenizer.A_CENTRE
assert processStyle("## Chapter\n", True) == Tokenizer.A_CENTRE
assert processStyle("### Scene\n", True) == Tokenizer.A_CENTRE
assert processStyle("#### Section\n", True) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", True) == Tokenizer.A_CENTRE
assert processStyle("##! Prologue\n", True) == Tokenizer.A_CENTRE
# Note Docs
tokens._isNovel = False
tokens._isNote = True
# First Document is False
assert processStyle("# Title\n", False) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", False) == Tokenizer.A_NONE
assert processStyle("### Scene\n", False) == Tokenizer.A_NONE
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_NONE
# First Document is True
assert processStyle("# Title\n", True) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", True) == Tokenizer.A_NONE
assert processStyle("### Scene\n", True) == Tokenizer.A_NONE
assert processStyle("#### Section\n", True) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", True) == Tokenizer.A_CENTRE
assert processStyle("##! Prologue\n", True) == Tokenizer.A_NONE
# Check Separation
# ================
tokens._isNovel = True
tokens._isNote = False
# Title Styles
tokens.setTitleStyle(True, True)
tokens.setChapterStyle(False, False)
tokens.setSceneStyle(False, False)
assert tokens._titleStyle == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert tokens._chapterStyle == Tokenizer.A_NONE
assert tokens._sceneStyle == Tokenizer.A_NONE
assert processStyle("# Title\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("## Chapter\n", False) == Tokenizer.A_NONE
assert processStyle("### Scene\n", False) == Tokenizer.A_NONE
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_NONE
# Chapter Styles
tokens.setTitleStyle(False, False)
tokens.setChapterStyle(True, True)
tokens.setSceneStyle(False, False)
assert tokens._titleStyle == Tokenizer.A_NONE
assert tokens._chapterStyle == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert tokens._sceneStyle == Tokenizer.A_NONE
assert processStyle("# Title\n", False) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("### Scene\n", False) == Tokenizer.A_NONE
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
# Scene Styles
tokens.setTitleStyle(False, False)
tokens.setChapterStyle(False, False)
tokens.setSceneStyle(True, True)
assert tokens._titleStyle == Tokenizer.A_NONE
assert tokens._chapterStyle == Tokenizer.A_NONE
assert tokens._sceneStyle == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("# Title\n", False) == Tokenizer.A_NONE
assert processStyle("## Chapter\n", False) == Tokenizer.A_NONE
assert processStyle("### Scene\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("#### Section\n", False) == Tokenizer.A_NONE
assert processStyle("#! My Novel\n", False) == Tokenizer.A_CENTRE | Tokenizer.A_PBB
assert processStyle("##! Prologue\n", False) == Tokenizer.A_NONE
# END Test testCoreToken_HeaderStyle
@pytest.mark.core @pytest.mark.core
def testCoreToken_MetaFormat(mockGUI): def testCoreToken_MetaFormat(mockGUI):
"""Test the tokenization of meta formats in the Tokenizer class.""" """Test the tokenization of meta formats in the Tokenizer class."""
@@ -520,6 +809,15 @@ def testCoreToken_MetaFormat(mockGUI):
] ]
assert tokens.allMarkdown[-1] == "@pov: Bod\n@plot: Main\n@location: Europe\n\n" assert tokens.allMarkdown[-1] == "@pov: Bod\n@plot: Main\n@location: Europe\n\n"
# Ignored keywords
tokens._text = "@pov: Bod\n@plot: Main\n@location: Europe\n"
tokens.setIgnoredKeywords("@plot, @location")
tokens.tokenizeText()
assert tokens._tokens == [
(Tokenizer.T_KEYWORD, 0, "pov: Bod", [], Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 0, "", [], Tokenizer.A_NONE),
]
# END Test testCoreToken_MetaFormat # END Test testCoreToken_MetaFormat
@@ -822,6 +1120,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"# Title Two\n\n" "# Title Two\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == correctResp assert tokens._tokens == correctResp
# Command w/Space # Command w/Space
@@ -832,6 +1131,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"# Title Two\n\n" "# Title Two\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == correctResp assert tokens._tokens == correctResp
# Trailing Spaces # Trailing Spaces
@@ -842,6 +1142,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"# Title Two\n\n" "# Title Two\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == correctResp assert tokens._tokens == correctResp
# Single Empty Paragraph # Single Empty Paragraph
@@ -853,6 +1154,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE), (Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -873,6 +1175,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE), (Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -890,6 +1193,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE), (Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -909,6 +1213,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE), (Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -925,6 +1230,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE), (Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -941,6 +1247,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE), (Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -961,6 +1268,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE), (Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
@@ -980,6 +1288,7 @@ def testCoreToken_SpecialFormat(mockGUI):
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
tokens.doHeaders()
assert tokens._tokens == [ assert tokens._tokens == [
(Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE), (Tokenizer.T_HEAD1, 1, "Title One", [], Tokenizer.A_PBB | Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE), (Tokenizer.T_EMPTY, 1, "", [], Tokenizer.A_NONE),
+10
View File
@@ -246,6 +246,7 @@ def testCoreToOdt_ConvertHeaders(mockGUI):
# Header 1 # Header 1
odt._text = "# Title\n" odt._text = "# Title\n"
odt.tokenizeText() odt.tokenizeText()
odt.doHeaders()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.closeDocument() odt.closeDocument()
@@ -259,6 +260,7 @@ def testCoreToOdt_ConvertHeaders(mockGUI):
# Header 2 # Header 2
odt._text = "## Chapter\n" odt._text = "## Chapter\n"
odt.tokenizeText() odt.tokenizeText()
odt.doHeaders()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.closeDocument() odt.closeDocument()
@@ -272,6 +274,7 @@ def testCoreToOdt_ConvertHeaders(mockGUI):
# Header 3 # Header 3
odt._text = "### Scene\n" odt._text = "### Scene\n"
odt.tokenizeText() odt.tokenizeText()
odt.doHeaders()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.closeDocument() odt.closeDocument()
@@ -285,6 +288,7 @@ def testCoreToOdt_ConvertHeaders(mockGUI):
# Header 4 # Header 4
odt._text = "#### Section\n" odt._text = "#### Section\n"
odt.tokenizeText() odt.tokenizeText()
odt.doHeaders()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.closeDocument() odt.closeDocument()
@@ -296,8 +300,10 @@ def testCoreToOdt_ConvertHeaders(mockGUI):
) )
# Title # Title
odt._isFirst = True
odt._text = "#! Title\n" odt._text = "#! Title\n"
odt.tokenizeText() odt.tokenizeText()
odt.doHeaders()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.closeDocument() odt.closeDocument()
@@ -311,6 +317,7 @@ def testCoreToOdt_ConvertHeaders(mockGUI):
# Unnumbered chapter # Unnumbered chapter
odt._text = "##! Prologue\n" odt._text = "##! Prologue\n"
odt.tokenizeText() odt.tokenizeText()
odt.doHeaders()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.closeDocument() odt.closeDocument()
@@ -605,6 +612,7 @@ def testCoreToOdt_ConvertParagraphs(mockGUI):
"Text\n\n" "Text\n\n"
) )
odt.tokenizeText() odt.tokenizeText()
odt.doHeaders()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.closeDocument() odt.closeDocument()
@@ -729,6 +737,7 @@ def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths):
"Text\n\n" "Text\n\n"
) )
odt.tokenizeText() odt.tokenizeText()
odt.doHeaders()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.closeDocument() odt.closeDocument()
@@ -768,6 +777,7 @@ def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths):
"Text\n\n" "Text\n\n"
) )
odt.tokenizeText() odt.tokenizeText()
odt.doHeaders()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.closeDocument() odt.closeDocument()
+13 -5
View File
@@ -479,10 +479,11 @@ def testBuildSettings_Content(qtbot: QtBot, nwGUI: GuiMain):
"""Test the Content Tab of the GuiBuildSettings dialog.""" """Test the Content Tab of the GuiBuildSettings dialog."""
build = BuildSettings() build = BuildSettings()
build.setValue("text.includeBodyText", False)
build.setValue("text.includeSynopsis", False) build.setValue("text.includeSynopsis", False)
build.setValue("text.includeComments", False) build.setValue("text.includeComments", False)
build.setValue("text.includeKeywords", False) build.setValue("text.includeKeywords", False)
build.setValue("text.includeBodyText", False) build.setValue("text.ignoredKeywords", "")
build.setValue("text.addNoteHeadings", False) build.setValue("text.addNoteHeadings", False)
@@ -496,28 +497,35 @@ def testBuildSettings_Content(qtbot: QtBot, nwGUI: GuiMain):
assert bSettings.toolStack.currentWidget() is contTab assert bSettings.toolStack.currentWidget() is contTab
# Check initial values # Check initial values
assert contTab.incBodyText.isChecked() is False
assert contTab.incSynopsis.isChecked() is False assert contTab.incSynopsis.isChecked() is False
assert contTab.incComments.isChecked() is False assert contTab.incComments.isChecked() is False
assert contTab.incKeywords.isChecked() is False assert contTab.incKeywords.isChecked() is False
assert contTab.incBodyText.isChecked() is False assert contTab.ignoredKeywords.text() == ""
assert contTab.addNoteHead.isChecked() is False assert contTab.addNoteHead.isChecked() is False
# Toggle all # Toggle switches
contTab.incBodyText.setChecked(True)
contTab.incSynopsis.setChecked(True) contTab.incSynopsis.setChecked(True)
contTab.incComments.setChecked(True) contTab.incComments.setChecked(True)
contTab.incKeywords.setChecked(True) contTab.incKeywords.setChecked(True)
contTab.incBodyText.setChecked(True)
contTab.addNoteHead.setChecked(True) contTab.addNoteHead.setChecked(True)
# Test cleanup of ignored keywords
contTab.ignoredKeywords.setText("@stuff, @pizza, @object") # First two are invalid
contTab._updateIgnoredKeywords("@custom") # Adding a new should trigger cleanup
assert contTab.ignoredKeywords.text() in ("@custom, @object", "@object, @custom")
# Save values # Save values
contTab.saveContent() contTab.saveContent()
assert build.getBool("text.includeBodyText") is True
assert build.getBool("text.includeSynopsis") is True assert build.getBool("text.includeSynopsis") is True
assert build.getBool("text.includeComments") is True assert build.getBool("text.includeComments") is True
assert build.getBool("text.includeKeywords") is True assert build.getBool("text.includeKeywords") is True
assert build.getBool("text.includeBodyText") is True assert build.getStr("text.ignoredKeywords") in ("@custom, @object", "@object, @custom")
assert build.getBool("text.addNoteHeadings") is True assert build.getBool("text.addNoteHeadings") is True