Add annotations to tokenizer, html and markdown classes

This commit is contained in:
Veronica Berglyd Olsen
2023-06-06 00:35:57 +02:00
parent 850ee73ed4
commit 6b6c517b1f
3 changed files with 177 additions and 166 deletions
+60 -63
View File
@@ -22,11 +22,15 @@ General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from __future__ import annotations
import logging import logging
from pathlib import Path
from novelwriter import CONFIG from novelwriter import CONFIG
from novelwriter.constants import nwKeyWords, nwLabels, nwHtmlUnicode from novelwriter.constants import nwKeyWords, nwLabels, nwHtmlUnicode
from novelwriter.core.project import NWProject
from novelwriter.core.tokenizer import Tokenizer, stripEscape from novelwriter.core.tokenizer import Tokenizer, stripEscape
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -38,8 +42,8 @@ class ToHtml(Tokenizer):
M_EXPORT = 1 # Tweak output for saving to HTML or printing M_EXPORT = 1 # Tweak output for saving to HTML or printing
M_EBOOK = 2 # Tweak output for converting to epub M_EBOOK = 2 # Tweak output for converting to epub
def __init__(self, theProject): def __init__(self, project: NWProject):
super().__init__(theProject) super().__init__(project)
self._genMode = self.M_EXPORT self._genMode = self.M_EXPORT
self._cssStyles = True self._cssStyles = True
@@ -63,7 +67,7 @@ class ToHtml(Tokenizer):
# Setters # Setters
## ##
def setPreview(self, doComments, doSynopsis): def setPreview(self, doComments: bool, doSynopsis: bool):
"""If we're using this class to generate markdown preview, we """If we're using this class to generate markdown preview, we
need to make a few changes to formatting, which is managed by need to make a few changes to formatting, which is managed by
these flags. these flags.
@@ -74,14 +78,14 @@ class ToHtml(Tokenizer):
self._doSynopsis = doSynopsis self._doSynopsis = doSynopsis
return return
def setStyles(self, cssStyles): def setStyles(self, cssStyles: bool):
"""Enable/disable CSS styling. Some elements may still have """Enable or disable CSS styling. Some elements may still have
class tags. class tags.
""" """
self._cssStyles = cssStyles self._cssStyles = cssStyles
return return
def setReplaceUnicode(self, doReplace): def setReplaceUnicode(self, doReplace: bool):
"""Set the translation map to either minimal or full unicode for """Set the translation map to either minimal or full unicode for
html entities replacement. html entities replacement.
""" """
@@ -92,16 +96,14 @@ class ToHtml(Tokenizer):
if doReplace: if doReplace:
# Extend to all relevant Unicode characters # Extend to all relevant Unicode characters
self._trMap.update(str.maketrans(nwHtmlUnicode.U_TO_H)) self._trMap.update(str.maketrans(nwHtmlUnicode.U_TO_H))
return return
## ##
# Class Methods # Class Methods
## ##
def getFullResultSize(self): def getFullResultSize(self) -> int:
"""Return the size of the full HTML result. """Return the size of the full HTML result."""
"""
return sum([len(x) for x in self._fullHTML]) return sum([len(x) for x in self._fullHTML])
def doPreProcessing(self): def doPreProcessing(self):
@@ -114,7 +116,7 @@ class ToHtml(Tokenizer):
def doConvert(self): def doConvert(self):
"""Convert the list of text tokens into a HTML document saved """Convert the list of text tokens into a HTML document saved
to theResult. to _result.
""" """
if self._genMode == self.M_PREVIEW: if self._genMode == self.M_PREVIEW:
htmlTags = { # HTML4 + CSS2 (for Qt) htmlTags = { # HTML4 + CSS2 (for Qt)
@@ -290,7 +292,7 @@ class ToHtml(Tokenizer):
return return
def saveHTML5(self, savePath): def saveHTML5(self, savePath: str | Path):
"""Save the data to an .html file. """Save the data to an .html file.
""" """
with open(savePath, mode="w", encoding="utf-8") as outFile: with open(savePath, mode="w", encoding="utf-8") as outFile:
@@ -324,9 +326,8 @@ class ToHtml(Tokenizer):
return return
def replaceTabs(self, nSpaces=8, spaceChar="&nbsp;"): def replaceTabs(self, nSpaces: int = 8, spaceChar: str = "&nbsp;"):
"""Replace tabs with spaces in the html. """Replace tabs with spaces in the html."""
"""
htmlText = [] htmlText = []
tabSpace = spaceChar*nSpaces tabSpace = spaceChar*nSpaces
for aLine in self._fullHTML: for aLine in self._fullHTML:
@@ -335,20 +336,19 @@ class ToHtml(Tokenizer):
self._fullHTML = htmlText self._fullHTML = htmlText
return return
def getStyleSheet(self): def getStyleSheet(self) -> list:
"""Generate a stylesheet appropriate for the current settings. """Generate a stylesheet for the current settings."""
""" styles = []
theStyles = []
if not self._cssStyles: if not self._cssStyles:
return theStyles return styles
mScale = self._lineHeight/1.15 mScale = self._lineHeight/1.15
textAlign = "justify" if self._doJustify else "left" textAlign = "justify" if self._doJustify else "left"
theStyles.append("body {{font-family: '{0:s}'; font-size: {1:d}pt;}}".format( styles.append("body {{font-family: '{0:s}'; font-size: {1:d}pt;}}".format(
self._textFont, self._textSize self._textFont, self._textSize
)) ))
theStyles.append(( styles.append((
"p {{" "p {{"
"text-align: {0}; line-height: {1:d}%; " "text-align: {0}; line-height: {1:d}%; "
"margin-top: {2:.2f}em; margin-bottom: {3:.2f}em;" "margin-top: {2:.2f}em; margin-bottom: {3:.2f}em;"
@@ -359,7 +359,7 @@ class ToHtml(Tokenizer):
mScale * self._marginText[0], mScale * self._marginText[0],
mScale * self._marginText[1], mScale * self._marginText[1],
)) ))
theStyles.append(( styles.append((
"h1 {{" "h1 {{"
"color: rgb(66, 113, 174); " "color: rgb(66, 113, 174); "
"page-break-after: avoid; " "page-break-after: avoid; "
@@ -369,7 +369,7 @@ class ToHtml(Tokenizer):
).format( ).format(
mScale * self._marginHead1[0], mScale * self._marginHead1[1] mScale * self._marginHead1[0], mScale * self._marginHead1[1]
)) ))
theStyles.append(( styles.append((
"h2 {{" "h2 {{"
"color: rgb(66, 113, 174); " "color: rgb(66, 113, 174); "
"page-break-after: avoid; " "page-break-after: avoid; "
@@ -379,7 +379,7 @@ class ToHtml(Tokenizer):
).format( ).format(
mScale * self._marginHead2[0], mScale * self._marginHead2[1] mScale * self._marginHead2[0], mScale * self._marginHead2[1]
)) ))
theStyles.append(( styles.append((
"h3 {{" "h3 {{"
"color: rgb(50, 50, 50); " "color: rgb(50, 50, 50); "
"page-break-after: avoid; " "page-break-after: avoid; "
@@ -389,7 +389,7 @@ class ToHtml(Tokenizer):
).format( ).format(
mScale * self._marginHead3[0], mScale * self._marginHead3[1] mScale * self._marginHead3[0], mScale * self._marginHead3[1]
)) ))
theStyles.append(( styles.append((
"h4 {{" "h4 {{"
"color: rgb(50, 50, 50); " "color: rgb(50, 50, 50); "
"page-break-after: avoid; " "page-break-after: avoid; "
@@ -399,7 +399,7 @@ class ToHtml(Tokenizer):
).format( ).format(
mScale * self._marginHead4[0], mScale * self._marginHead4[1] mScale * self._marginHead4[0], mScale * self._marginHead4[1]
)) ))
theStyles.append(( styles.append((
".title {{" ".title {{"
"font-size: 2.5em; " "font-size: 2.5em; "
"margin-top: {0:.2f}em; " "margin-top: {0:.2f}em; "
@@ -408,7 +408,7 @@ class ToHtml(Tokenizer):
).format( ).format(
mScale * self._marginTitle[0], mScale * self._marginTitle[1] mScale * self._marginTitle[0], mScale * self._marginTitle[1]
)) ))
theStyles.append(( styles.append((
".sep, .skip {{" ".sep, .skip {{"
"text-align: center; " "text-align: center; "
"margin-top: {0:.2f}em; " "margin-top: {0:.2f}em; "
@@ -418,61 +418,58 @@ class ToHtml(Tokenizer):
mScale, mScale mScale, mScale
)) ))
theStyles.append("a {color: rgb(66, 113, 174);}") styles.append("a {color: rgb(66, 113, 174);}")
theStyles.append(".tags {color: rgb(245, 135, 31); font-weight: bold;}") styles.append(".tags {color: rgb(245, 135, 31); font-weight: bold;}")
theStyles.append(".break {text-align: left;}") styles.append(".break {text-align: left;}")
theStyles.append(".synopsis {font-style: italic;}") styles.append(".synopsis {font-style: italic;}")
theStyles.append(".comment {font-style: italic; color: rgb(100, 100, 100);}") styles.append(".comment {font-style: italic; color: rgb(100, 100, 100);}")
return theStyles return styles
## ##
# Internal Functions # Internal Functions
## ##
def _formatSynopsis(self, tText): def _formatSynopsis(self, text: str) -> str:
"""Apply HTML formatting to synopsis. """Apply HTML formatting to synopsis."""
"""
if self._genMode == self.M_PREVIEW: if self._genMode == self.M_PREVIEW:
sSynop = self._trSynopsis sSynop = self._trSynopsis
return f"<p class='comment'><span class='synopsis'>{sSynop}:</span> {tText}</p>\n" return f"<p class='comment'><span class='synopsis'>{sSynop}:</span> {text}</p>\n"
else: else:
sSynop = self._localLookup("Synopsis") sSynop = self._localLookup("Synopsis")
return f"<p class='synopsis'><strong>{sSynop}:</strong> {tText}</p>\n" return f"<p class='synopsis'><strong>{sSynop}:</strong> {text}</p>\n"
def _formatComments(self, tText): def _formatComments(self, text: str) -> str:
"""Apply HTML formatting to comments. """Apply HTML formatting to comments."""
"""
if self._genMode == self.M_PREVIEW: if self._genMode == self.M_PREVIEW:
return f"<p class='comment'>{tText}</p>\n" return f"<p class='comment'>{text}</p>\n"
else: else:
sComm = self._localLookup("Comment") sComm = self._localLookup("Comment")
return f"<p class='comment'><strong>{sComm}:</strong> {tText}</p>\n" return f"<p class='comment'><strong>{sComm}:</strong> {text}</p>\n"
def _formatKeywords(self, tText): def _formatKeywords(self, text: str) -> str:
"""Apply HTML formatting to keywords. """Apply HTML formatting to keywords."""
""" valid, bits, _ = self._project.index.scanThis("@"+text)
isValid, theBits, _ = self._project.index.scanThis("@"+tText) if not valid or not bits:
if not isValid or not theBits:
return "" return ""
retText = "" result = ""
refTags = [] tags = []
if theBits[0] in nwLabels.KEY_NAME: if bits[0] in nwLabels.KEY_NAME:
retText += f"<span class='tags'>{nwLabels.KEY_NAME[theBits[0]]}:</span> " result += f"<span class='tags'>{nwLabels.KEY_NAME[bits[0]]}:</span> "
if len(theBits) > 1: if len(bits) > 1:
if theBits[0] == nwKeyWords.TAG_KEY: if bits[0] == nwKeyWords.TAG_KEY:
retText += f"<a name='tag_{theBits[1]}'>{theBits[1]}</a>" result += f"<a name='tag_{bits[1]}'>{bits[1]}</a>"
else: else:
if self._genMode == self.M_PREVIEW: if self._genMode == self.M_PREVIEW:
for tTag in theBits[1:]: for tTag in bits[1:]:
refTags.append(f"<a href='#{theBits[0][1:]}={tTag}'>{tTag}</a>") tags.append(f"<a href='#{bits[0][1:]}={tTag}'>{tTag}</a>")
retText += ", ".join(refTags) result += ", ".join(tags)
else: else:
for tTag in theBits[1:]: for tTag in bits[1:]:
refTags.append(f"<a href='#tag_{tTag}'>{tTag}</a>") tags.append(f"<a href='#tag_{tTag}'>{tTag}</a>")
retText += ", ".join(refTags) result += ", ".join(tags)
return retText return result
# END Class ToHtml # END Class ToHtml
+88 -65
View File
@@ -29,6 +29,7 @@ import re
import logging import logging
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from pathlib import Path
from operator import itemgetter from operator import itemgetter
from functools import partial from functools import partial
@@ -102,7 +103,7 @@ class Tokenizer(ABC):
self._result = "" # The result of the last document self._result = "" # The result of the last document
self._keepMarkdown = False # Whether to keep the markdown text self._keepMarkdown = False # Whether to keep the markdown text
self._theMarkdown = [] # The result novelWriter markdown of all documents self._allMarkdown = [] # The result novelWriter markdown of all documents
# User Settings # User Settings
self._textFont = "Serif" # Output text font self._textFont = "Serif" # Output text font
@@ -164,111 +165,136 @@ class Tokenizer(ABC):
## ##
@property @property
def theResult(self): def theResult(self) -> str:
"""The result of the build process."""
return self._result return self._result
@property @property
def theMarkdown(self): def theMarkdown(self) -> list:
return self._theMarkdown """The combined novelWriter Markdown text."""
return self._allMarkdown
@property @property
def errData(self): def errData(self) -> list:
"""The error data."""
return self._errData return self._errData
## ##
# Setters # Setters
## ##
def setTitleFormat(self, hFormat): def setTitleFormat(self, hFormat: str):
"""Set the title format pattern."""
self._fmtTitle = hFormat.strip() self._fmtTitle = hFormat.strip()
return return
def setChapterFormat(self, hFormat): def setChapterFormat(self, hFormat: str):
"""Set the chapert format pattern."""
self._fmtChapter = hFormat.strip() self._fmtChapter = hFormat.strip()
return return
def setUnNumberedFormat(self, hFormat): def setUnNumberedFormat(self, hFormat: str):
"""Set the unnumbered format pattern."""
self._fmtUnNum = hFormat.strip() self._fmtUnNum = hFormat.strip()
return return
def setSceneFormat(self, hFormat, hide): def setSceneFormat(self, hFormat: str, hide: bool):
"""Set the scene format pattern and hidden status."""
self._fmtScene = hFormat.strip() self._fmtScene = hFormat.strip()
self._hideScene = hide self._hideScene = hide
return return
def setSectionFormat(self, hFormat, hide): def setSectionFormat(self, hFormat: str, hide: bool):
"""Set the section format pattern and hidden status."""
self._fmtSection = hFormat.strip() self._fmtSection = hFormat.strip()
self._hideSection = hide self._hideSection = hide
return return
def setFont(self, textFont, textSize, textFixed=False): def setFont(self, family: str, size: int, isFixed: bool = False):
self._textFont = textFont """Set the build font."""
self._textSize = round(int(textSize)) self._textFont = family
self._textFixed = textFixed self._textSize = round(int(size))
self._textFixed = isFixed
return return
def setLineHeight(self, lineHeight): def setLineHeight(self, height: float):
self._lineHeight = min(max(float(lineHeight), 0.5), 5.0) """Set the line height between 0.5 and 5.0."""
self._lineHeight = min(max(float(height), 0.5), 5.0)
return return
def setBlockIndent(self, blockIndent): def setBlockIndent(self, indent: float):
self._blockIndent = min(max(float(blockIndent), 0.0), 10.0) """Set the block indent between 0.0 and 10.0."""
self._blockIndent = min(max(float(indent), 0.0), 10.0)
return return
def setJustify(self, doJustify): def setJustify(self, state: bool):
self._doJustify = doJustify """Enable or disable text justification."""
self._doJustify = state
return return
def setTitleMargins(self, mUpper, mLower): def setTitleMargins(self, upper: float, lower: float):
self._marginTitle = (float(mUpper), float(mLower)) """Set the upper and lower title margin."""
self._marginTitle = (float(upper), float(lower))
return return
def setHead1Margins(self, mUpper, mLower): def setHead1Margins(self, upper: float, lower: float):
self._marginHead1 = (float(mUpper), float(mLower)) """Set the upper and lower header 1 margin."""
self._marginHead1 = (float(upper), float(lower))
return return
def setHead2Margins(self, mUpper, mLower): def setHead2Margins(self, upper: float, lower: float):
self._marginHead2 = (float(mUpper), float(mLower)) """Set the upper and lower header 2 margin."""
self._marginHead2 = (float(upper), float(lower))
return return
def setHead3Margins(self, mUpper, mLower): def setHead3Margins(self, upper: float, lower: float):
self._marginHead3 = (float(mUpper), float(mLower)) """Set the upper and lower header 3 margin."""
self._marginHead3 = (float(upper), float(lower))
return return
def setHead4Margins(self, mUpper, mLower): def setHead4Margins(self, upper: float, lower: float):
self._marginHead4 = (float(mUpper), float(mLower)) """Set the upper and lower header 4 margin."""
self._marginHead4 = (float(upper), float(lower))
return return
def setTextMargins(self, mUpper, mLower): def setTextMargins(self, upper: float, lower: float):
self._marginText = (float(mUpper), float(mLower)) """Set the upper and lower text margin."""
self._marginText = (float(upper), float(lower))
return return
def setMetaMargins(self, mUpper, mLower): def setMetaMargins(self, upper: float, lower: float):
self._marginMeta = (float(mUpper), float(mLower)) """Set the upper and lower meta text margin."""
self._marginMeta = (float(upper), float(lower))
return return
def setLinkHeaders(self, linkHeaders): def setLinkHeaders(self, state: bool):
self._linkHeaders = linkHeaders """Enable or disable adding an anchor before headers."""
self._linkHeaders = state
return return
def setBodyText(self, doBodyText): def setBodyText(self, state: bool):
self._doBodyText = doBodyText """Include body text in build."""
self._doBodyText = state
return return
def setSynopsis(self, doSynopsis): def setSynopsis(self, state: bool):
self._doSynopsis = doSynopsis """Include synopsis comments in build."""
self._doSynopsis = state
return return
def setComments(self, doComments): def setComments(self, state: bool):
self._doComments = doComments """Include comments in build."""
self._doComments = state
return return
def setKeywords(self, doKeywords): def setKeywords(self, state: bool):
self._doKeywords = doKeywords """Include keywords in build."""
self._doKeywords = state
return return
def setKeepMarkdown(self, keepMarkdown): def setKeepMarkdown(self, state: bool):
self._keepMarkdown = keepMarkdown """Keep original markdown during build."""
self._keepMarkdown = state
return return
## ##
@@ -279,10 +305,9 @@ class Tokenizer(ABC):
def doConvert(self): def doConvert(self):
raise NotImplementedError raise NotImplementedError
def addRootHeading(self, theHandle): def addRootHeading(self, tHandle: str) -> bool:
"""Add a heading at the start of a new root folder. """Add a heading at the start of a new root folder."""
""" if not self._project.tree.checkType(tHandle, nwItemType.ROOT):
if not self._project.tree.checkType(theHandle, nwItemType.ROOT):
return False return False
if self._isFirst: if self._isFirst:
@@ -291,7 +316,7 @@ class Tokenizer(ABC):
else: else:
textAlign = self.A_PBB | self.A_CENTRE textAlign = self.A_PBB | self.A_CENTRE
theItem = self._project.tree[theHandle] theItem = self._project.tree[tHandle]
locNotes = self._localLookup("Notes") locNotes = self._localLookup("Notes")
theTitle = f"{locNotes}: {theItem.itemName}" theTitle = f"{locNotes}: {theItem.itemName}"
self._tokens = [] self._tokens = []
@@ -299,22 +324,22 @@ class Tokenizer(ABC):
self.T_TITLE, 0, theTitle, None, textAlign self.T_TITLE, 0, theTitle, None, textAlign
)) ))
if self._keepMarkdown: if self._keepMarkdown:
self._theMarkdown.append(f"# {theTitle}\n\n") self._allMarkdown.append(f"# {theTitle}\n\n")
return True return True
def setText(self, theHandle, theText=None): def setText(self, tHandle: str, text: str | None = None) -> bool:
"""Set the text for the tokenizer from a handle. If theText is """Set the text for the tokenizer from a handle. If theText is
not set, load it from the file. not set, load it from the file.
""" """
self._nwItem = self._project.tree[theHandle] self._nwItem = self._project.tree[tHandle]
if self._nwItem is None: if self._nwItem is None:
return False return False
if theText is None: if text is None:
theText = self._project.storage.getDocument(theHandle).readDocument() or "" text = self._project.storage.getDocument(tHandle).readDocument() or ""
self._text = theText self._text = text
docSize = len(self._text) docSize = len(self._text)
if docSize > nwConst.MAX_DOCSIZE: if docSize > nwConst.MAX_DOCSIZE:
@@ -331,8 +356,7 @@ class Tokenizer(ABC):
return True return True
def doPreProcessing(self): def doPreProcessing(self):
"""Run trough the various replace doctionaries. """Run trough the various replace dictionaries."""
"""
# Process the user's auto-replace dictionary # Process the user's auto-replace dictionary
autoReplace = self._project.data.autoReplace autoReplace = self._project.data.autoReplace
if len(autoReplace) > 0: if len(autoReplace) > 0:
@@ -582,7 +606,7 @@ class Tokenizer(ABC):
tmpMarkdown.append("\n") tmpMarkdown.append("\n")
if self._keepMarkdown: if self._keepMarkdown:
self._theMarkdown.append("".join(tmpMarkdown)) self._allMarkdown.append("".join(tmpMarkdown))
# Second Pass # Second Pass
# =========== # ===========
@@ -610,7 +634,7 @@ class Tokenizer(ABC):
return return
def doHeaders(self): def doHeaders(self) -> bool:
"""Apply formatting to the text headers for novel files. This """Apply formatting to the text headers for novel files. This
also applies chapter and scene numbering. also applies chapter and scene numbering.
""" """
@@ -708,11 +732,10 @@ class Tokenizer(ABC):
return True return True
def saveRawMarkdown(self, savePath): def saveRawMarkdown(self, savePath: str | Path):
"""Save the data to a plain text file. """Save the data to a plain text file."""
"""
with open(savePath, mode="w", encoding="utf-8") as outFile: with open(savePath, mode="w", encoding="utf-8") as outFile:
for nwdPage in self._theMarkdown: for nwdPage in self._allMarkdown:
outFile.write(nwdPage) outFile.write(nwdPage)
return return
+29 -38
View File
@@ -22,10 +22,14 @@ General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from __future__ import annotations
import logging import logging
from pathlib import Path
from novelwriter.constants import nwLabels from novelwriter.constants import nwLabels
from novelwriter.core.project import NWProject
from novelwriter.core.tokenizer import Tokenizer from novelwriter.core.tokenizer import Tokenizer
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -36,8 +40,8 @@ class ToMarkdown(Tokenizer):
M_STD = 0 # Standard Markdown M_STD = 0 # Standard Markdown
M_GH = 1 # GitHub Markdown M_GH = 1 # GitHub Markdown
def __init__(self, theProject): def __init__(self, project: NWProject):
super().__init__(theProject) super().__init__(project)
self._genMode = self.M_STD self._genMode = self.M_STD
self._fullMD = [] self._fullMD = []
@@ -49,7 +53,8 @@ class ToMarkdown(Tokenizer):
## ##
@property @property
def fullMD(self): def fullMD(self) -> list:
"""Return the markdown as a list."""
return self._fullMD return self._fullMD
## ##
@@ -68,9 +73,8 @@ class ToMarkdown(Tokenizer):
# Class Methods # Class Methods
## ##
def getFullResultSize(self): def getFullResultSize(self) -> int:
"""Return the size of the full Markdown result. """Return the size of the full Markdown result."""
"""
return sum([len(x) for x in self._fullMD]) return sum([len(x) for x in self._fullMD])
def doConvert(self): def doConvert(self):
@@ -166,49 +170,36 @@ class ToMarkdown(Tokenizer):
return return
def saveMarkdown(self, savePath): def saveMarkdown(self, path: str | Path):
"""Save the data to a plain text file. """Save the data to a plain text file."""
""" with open(path, mode="w", encoding="utf-8") as outFile:
with open(savePath, mode="w", encoding="utf-8") as outFile: outFile.write("".join(self._fullMD))
theText = "".join(self._fullMD)
outFile.write(theText)
return return
def replaceTabs(self, nSpaces=8, spaceChar=" "): def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " "):
"""Replace tabs with spaces. """Replace tabs with spaces."""
""" spaces = spaceChar*nSpaces
fullMD = [] self._fullMD = [p.replace("\t", spaces) for p in self._fullMD]
eightSpace = spaceChar*nSpaces
for aPage in self._fullMD:
fullMD.append(aPage.replace("\t", eightSpace))
self._fullMD = fullMD
return return
## ##
# Internal Functions # Internal Functions
## ##
def _formatKeywords(self, tText, tStyle): def _formatKeywords(self, text: str, style: int) -> str:
"""Apply Markdown formatting to keywords. """Apply Markdown formatting to keywords."""
""" valid, bits, _ = self._project.index.scanThis("@"+text)
isValid, theBits, _ = self._project.index.scanThis("@"+tText) if not valid or not bits:
if not isValid or not theBits:
return "" return ""
retText = "" result = ""
if theBits[0] in nwLabels.KEY_NAME: if bits[0] in nwLabels.KEY_NAME:
retText += f"**{nwLabels.KEY_NAME[theBits[0]]}:** " result += f"**{nwLabels.KEY_NAME[bits[0]]}:** "
if len(bits) > 1:
result += ", ".join(bits[1:])
if len(theBits) > 1: result += " \n" if style & self.A_Z_BTMMRG else "\n\n"
retText += ", ".join(theBits[1:])
if tStyle & self.A_Z_BTMMRG: return result
retText += " \n"
else:
retText += "\n\n"
return retText
# END Class ToMarkdown # END Class ToMarkdown