diff --git a/nw/core/tohtml.py b/nw/core/tohtml.py index df6c4a09..f3166d02 100644 --- a/nw/core/tohtml.py +++ b/nw/core/tohtml.py @@ -68,16 +68,16 @@ class ToHtml(Tokenizer): # Setters ## - def setPreview(self, forPreview, doComments, doSynopsis): + def setPreview(self, doComments, doSynopsis): """If we're using this class to generate markdown preview, we need to make a few changes to formatting, which is managed by these flags. """ - if forPreview: - self.genMode = self.M_PREVIEW - self.doKeywords = True - self.doComments = doComments - self.doSynopsis = doSynopsis + self.genMode = self.M_PREVIEW + self.doKeywords = True + self.doComments = doComments + self.doSynopsis = doSynopsis + return def setStyles(self, cssStyles): @@ -141,11 +141,13 @@ class ToHtml(Tokenizer): # For novel files for export, we bump the titles one level # up as this is more useful for printing and word processor # imports. - h1 = "h1 class='title'" + h1Cl = " class='title'" + h1 = "h1" h2 = "h1" h3 = "h2" h4 = "h3" else: + h1Cl = "" h1 = "h1" h2 = "h2" h3 = "h3" @@ -193,7 +195,7 @@ class ToHtml(Tokenizer): else: aNm = "" - # Process TextType + # Process Text Type if tType == self.T_EMPTY: if parStyle is None: parStyle = "" @@ -214,7 +216,7 @@ class ToHtml(Tokenizer): elif tType == self.T_HEAD1: tHead = tText.replace(r"\\", "
") - tmpResult.append("<%s%s>%s%s\n" % (h1, hStyle, aNm, tHead, h1)) + tmpResult.append("<%s%s%s>%s%s\n" % (h1, h1Cl, hStyle, aNm, tHead, h1)) elif tType == self.T_HEAD2: tHead = tText.replace(r"\\", "
") diff --git a/nw/gui/docviewer.py b/nw/gui/docviewer.py index e74e7ada..f3badad5 100644 --- a/nw/gui/docviewer.py +++ b/nw/gui/docviewer.py @@ -169,7 +169,7 @@ class GuiDocViewer(QTextBrowser): sPos = self.verticalScrollBar().value() aDoc = ToHtml(self.theProject, self.theParent) - aDoc.setPreview(True, self.mainConf.viewComments, self.mainConf.viewSynopsis) + aDoc.setPreview(self.mainConf.viewComments, self.mainConf.viewSynopsis) aDoc.setLinkHeaders(True) # Be extra careful here to prevent crashes when first opening a diff --git a/nw/guimain.py b/nw/guimain.py index 801de5af..76b344fb 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -81,14 +81,14 @@ class GuiMain(QMainWindow): # Core Classes # ============ - # Core Classes and settings + # Core Classes and Settings self.theTheme = GuiTheme(self) self.theProject = NWProject(self) self.theIndex = NWIndex(self.theProject, self) self.hasProject = False self.isFocusMode = False - # Prepare main window + # Prepare Main Window self.resize(*self.mainConf.getWinSize()) self._setWindowTitle() self.setWindowIcon(QIcon(self.mainConf.appIcon)) @@ -1073,10 +1073,10 @@ class GuiMain(QMainWindow): self.isFocusMode = not self.isFocusMode if self.isFocusMode: - logger.debug("Activating Focus mode") + logger.debug("Activating Focus Mode") self.tabWidget.setCurrentWidget(self.splitDocs) else: - logger.debug("Deactivating Focus mode") + logger.debug("Deactivating Focus Mode") isVisible = not self.isFocusMode self.treePane.setVisible(isVisible) diff --git a/tests/dummy.py b/tests/dummy.py index fbb91cbd..803e4e12 100644 --- a/tests/dummy.py +++ b/tests/dummy.py @@ -11,6 +11,8 @@ class DummyMain(): def __init__(self): self.mainConf = None self.hasProject = True + self.theIndex = None + self.theProject = None self.statusBar = StatusBar() return diff --git a/tests/test_core_tohtml.py b/tests/test_core_tohtml.py new file mode 100644 index 00000000..7c228edf --- /dev/null +++ b/tests/test_core_tohtml.py @@ -0,0 +1,373 @@ +# -*- coding: utf-8 -*- +"""novelWriter ToHtml Class Tester +""" + +import pytest + +from nw.core import NWProject, NWIndex, ToHtml + +@pytest.mark.core +def testCoreToHtml_Format(dummyGUI): + """Test all the formatters for the ToHtml class. + """ + theProject = NWProject(dummyGUI) + dummyGUI.theIndex = NWIndex(theProject, dummyGUI) + theHtml = ToHtml(theProject, dummyGUI) + + # Export Mode + # =========== + + assert theHtml._formatSynopsis("synopsis text") == ( + "

Synopsis: synopsis text

\n" + ) + assert theHtml._formatComments("comment text") == ( + "

Comment: comment text

\n" + ) + + assert theHtml._formatKeywords("") == "" + assert theHtml._formatKeywords("tag: Jane") == ( + "
Tag: Jane
" + ) + assert theHtml._formatKeywords("char: Bod, Jane") == ( + "
" + "Characters: " + "Bod, " + "Jane" + "
" + ) + + # Preview Mode + # ============ + + theHtml.setPreview(True, True) + + assert theHtml._formatSynopsis("synopsis text") == ( + "

Synopsis: synopsis text

\n" + ) + assert theHtml._formatComments("comment text") == ( + "

comment text

\n" + ) + + assert theHtml._formatKeywords("") == "" + assert theHtml._formatKeywords("tag: Jane") == ( + "
Tag: Jane
" + ) + assert theHtml._formatKeywords("char: Bod, Jane") == ( + "
" + "Characters: " + "Bod, " + "Jane" + "
" + ) + +# END Test testCoreToHtml_Format + +@pytest.mark.core +def testCoreToHtml_Convert(dummyGUI): + """Test the converter of the ToHtml class. + """ + theProject = NWProject(dummyGUI) + dummyGUI.theIndex = NWIndex(theProject, dummyGUI) + theHtml = ToHtml(theProject, dummyGUI) + + # Export Mode + # =========== + + theHtml.isNovel = True + + # Header 1 + theHtml.theText = "# Title\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "

Title

\n" + + # Header 2 + theHtml.theText = "## Chapter Title\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "

Chapter Title

\n" + + # Header 3 + theHtml.theText = "### Scene Title\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "

Scene Title

\n" + + # Header 4 + theHtml.theText = "#### Section Title\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "

Section Title

\n" + + theHtml.isNovel = False + theHtml.setLinkHeaders(True) + + # Header 1 + theHtml.theText = "# Heading One\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "

Heading One

\n" + + # Header 2 + theHtml.theText = "## Heading Two\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "

Heading Two

\n" + + # Header 3 + theHtml.theText = "### Heading Three\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "

Heading Three

\n" + + # Header 4 + theHtml.theText = "#### Heading Four\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "

Heading Four

\n" + + # Text + theHtml.theText = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == ( + "

Some nested bold and italic and " + "strikethrough text here

\n" + ) + + # Text w/Hard Break + theHtml.theText = "Line one \nLine two \nLine three\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == ( + "

Line one
Line two
Line three

\n" + ) + + # Synopsis + theHtml.theText = "%synopsis: The synopsis ...\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "" + + theHtml.setSynopsis(True) + theHtml.theText = "%synopsis: The synopsis ...\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == ( + "

Synopsis: The synopsis ...

\n" + ) + + # Comment + theHtml.theText = "% A comment ...\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "" + + theHtml.setComments(True) + theHtml.theText = "% A comment ...\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == ( + "

Comment: A comment ...

\n" + ) + + # Keywords + theHtml.theText = "@char: Bod, Jane\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == "" + + theHtml.setKeywords(True) + theHtml.theText = "@char: Bod, Jane\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == ( + "
Characters: " + "Bod, Jane
" + ) + + # Direct Tests + # ============ + + theHtml.isNovel = True + + # Title + theHtml.theTokens = [ + (theHtml.T_TITLE, 1, "A Title", None, theHtml.A_PBB_NO | theHtml.A_CENTRE), + (theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE), + ] + theHtml.doConvert() + assert theHtml.theResult == ( + "

" + "A Title

\n" + ) + + # Separator + theHtml.theTokens = [ + (theHtml.T_SEP, 1, "* * *", None, theHtml.A_CENTRE), + (theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE), + ] + theHtml.doConvert() + assert theHtml.theResult == "

* * *

\n" + + # Skip + theHtml.theTokens = [ + (theHtml.T_SKIP, 1, "", None, theHtml.A_NONE), + (theHtml.T_EMPTY, 1, "", None, theHtml.A_NONE), + ] + theHtml.doConvert() + assert theHtml.theResult == "

 

\n" + + # Styles + # ====== + + theHtml.setLinkHeaders(False) + + # Align Left + theHtml.setStyles(False) + theHtml.theTokens = [ + (theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_LEFT), + ] + theHtml.doConvert() + assert theHtml.theResult == ( + "

A Title

\n" + ) + + theHtml.setStyles(True) + + # Align Left + theHtml.theTokens = [ + (theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_LEFT), + ] + theHtml.doConvert() + assert theHtml.theResult == ( + "

A Title

\n" + ) + + # Align Right + theHtml.theTokens = [ + (theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_RIGHT), + ] + theHtml.doConvert() + assert theHtml.theResult == ( + "

A Title

\n" + ) + + # Align Centre + theHtml.theTokens = [ + (theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_CENTRE), + ] + theHtml.doConvert() + assert theHtml.theResult == ( + "

A Title

\n" + ) + + # Align Justify + theHtml.theTokens = [ + (theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_JUSTIFY), + ] + theHtml.doConvert() + assert theHtml.theResult == ( + "

A Title

\n" + ) + + # Page Break Always + theHtml.theTokens = [ + (theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_PBB | theHtml.A_PBA), + ] + theHtml.doConvert() + assert theHtml.theResult == ( + "

A Title

\n" + ) + + # Page Break Avoid + theHtml.theTokens = [ + (theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_PBB_AV | theHtml.A_PBA_AV), + ] + theHtml.doConvert() + assert theHtml.theResult == ( + "

A Title

\n" + ) + + # Page Break ANever + theHtml.theTokens = [ + (theHtml.T_HEAD1, 1, "A Title", None, theHtml.A_PBB_NO | theHtml.A_PBA_NO), + ] + theHtml.doConvert() + assert theHtml.theResult == ( + "

A Title

\n" + ) + + # Preview Mode + # ============ + + theHtml.setPreview(True, True) + + # Text (HTML4) + theHtml.theText = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n" + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == ( + "

Some nested bold and italic and " + "strikethrough " + "text here

\n" + ) + +# END Test testCoreToHtml_Convert + +@pytest.mark.core +def testCoreToHtml_Methods(dummyGUI): + """Test all the other methods of the ToHtml class. + """ + theProject = NWProject(dummyGUI) + theHtml = ToHtml(theProject, dummyGUI) + + # Auto-Replace + docText = "Text with & short–dash, long—dash …\n" + theHtml.theText = docText + theHtml.doAutoReplace() + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theResult == ( + "

Text with <brackets> & short–dash, long—dash …

\n" + ) + + # Revert on MD + assert theHtml.theMarkdown == ( + "Text with <brackets> & short–dash, long—dash …\n\n" + ) + theHtml.doPostProcessing() + assert theHtml.theMarkdown == docText + "\n" + + # With Preview, No Revert + theHtml.setPreview(True, True) + theHtml.theText = docText + theHtml.doAutoReplace() + theHtml.tokenizeText() + theHtml.doConvert() + assert theHtml.theMarkdown == ( + "Text with <brackets> & short–dash, long—dash …\n\n" + ) + theHtml.doPostProcessing() + assert theHtml.theMarkdown == ( + "Text with <brackets> & short–dash, long—dash …\n\n" + ) + + # CSS + # === + + assert len(theHtml.getStyleSheet()) > 1 + assert "p {text-align: left;}" in theHtml.getStyleSheet() + assert "p {text-align: justify;}" not in theHtml.getStyleSheet() + + theHtml.setJustify(True) + assert "p {text-align: left;}" not in theHtml.getStyleSheet() + assert "p {text-align: justify;}" in theHtml.getStyleSheet() + + theHtml.setStyles(False) + assert theHtml.getStyleSheet() == [] + +# END Test testCoreToHtml_Methods diff --git a/tests/test_core_tokenizer.py b/tests/test_core_tokenizer.py index 559f3a1e..3d0774b5 100644 --- a/tests/test_core_tokenizer.py +++ b/tests/test_core_tokenizer.py @@ -12,7 +12,7 @@ def testCoreToken_Setters(dummyGUI): """Test all the setters for the Tokenizer class. """ theProject = NWProject(dummyGUI) - theToken = Tokenizer(dummyGUI, theProject) + theToken = Tokenizer(theProject, dummyGUI) # Verify defaults assert theToken.fmtTitle == "%title%" @@ -600,7 +600,6 @@ def testCoreToken_Headers(dummyGUI): # H1: Title theToken.theText = "# Novel Title\n" - theToken.setTitleFormat(r"T: %title%") theToken.tokenizeText() theToken.isTitle = True theToken.isPart = False