From c7a42a1641494a5a6399b686dc99a3b366d073a1 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sat, 6 Feb 2021 15:07:08 +0100 Subject: [PATCH] Basic to markdown class added --- nw/core/tomd.py | 217 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 nw/core/tomd.py diff --git a/nw/core/tomd.py b/nw/core/tomd.py new file mode 100644 index 00000000..35bcdf47 --- /dev/null +++ b/nw/core/tomd.py @@ -0,0 +1,217 @@ +# -*- coding: utf-8 -*- +""" +novelWriter – Markdown Text Converter +===================================== +Extends the Tokenizer class to generate Makrdown output + +File History: +Created: 2021-02-06 [1.2a0] + +This file is a part of novelWriter +Copyright 2018–2021, Veronica Berglyd Olsen + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +import logging + +from nw.core.tokenizer import Tokenizer +from nw.constants import nwLabels + +logger = logging.getLogger(__name__) + +class ToMarkdown(Tokenizer): + + M_STD = 0 # Standard Markdown + M_GH = 1 # GitHub Markdown + M_NW = 2 # novelWriter Markdown + + def __init__(self, theProject, theParent): + Tokenizer.__init__(self, theProject, theParent) + + self.genMode = self.M_STD + self.fullMD = [] + + return + + ## + # Setters + ## + + def setStandardMarkdown(self): + self.genMode = self.M_STD + return + + def setGitHubMarkdown(self): + self.genMode = self.M_GH + return + + def setNovelWriterMarkdown(self): + self.genMode = self.M_MD + return + + ## + # Class Methods + ## + + def getFullResultSize(self): + """Return the size of the full Markdown result. + """ + return sum([len(x) for x in self.fullMD]) + + def doConvert(self): + """Convert the list of text tokens into a HTML document saved + to theResult. + """ + if self.genMode == self.M_STD: + # Standard + mdTags = { + self.FMT_B_B : "**", self.FMT_B_E : "**", + self.FMT_I_B : "_", self.FMT_I_E : "_", + self.FMT_D_B : "", self.FMT_D_E : "", + } + else: + # GitHub and novelWriter + mdTags = { + self.FMT_B_B : "**", self.FMT_B_E : "**", + self.FMT_I_B : "_", self.FMT_I_E : "_", + self.FMT_D_B : "~~", self.FMT_D_E : "~~", + } + + self.theResult = "" + + thisPar = [] + tmpResult = [] + + for tType, tLine, tText, tFormat, tStyle in self.theTokens: + + # Process Text Type + if tType == self.T_EMPTY: + if len(thisPar) > 0: + tTemp = "".join(thisPar) + tmpResult.append("%s\n" % tTemp) + + thisPar = [] + + elif tType == self.T_TITLE: + tHead = tText.replace(r"\\", "\n") + tmpResult.append("# %s\n" % tHead) + + elif tType == self.T_HEAD1: + tHead = tText.replace(r"\\", "\n") + tmpResult.append("# %s\n" % tHead) + + elif tType == self.T_HEAD2: + tHead = tText.replace(r"\\", "\n") + tmpResult.append("## %s\n" % tHead) + + elif tType == self.T_HEAD3: + tHead = tText.replace(r"\\", "\n") + tmpResult.append("### %s\n" % tHead) + + elif tType == self.T_HEAD4: + tHead = tText.replace(r"\\", "\n") + tmpResult.append("#### %s\n" % tHead) + + elif tType == self.T_SEP: + tmpResult.append("%s\n\n" % tText) + + elif tType == self.T_SKIP: + tmpResult.append("\n\n\n") + + elif tType == self.T_TEXT: + tTemp = tText + for xPos, xLen, xFmt in reversed(tFormat): + tTemp = tTemp[:xPos] + mdTags[xFmt] + tTemp[xPos+xLen:] + if tText.endswith(" "): + thisPar.append(tTemp.rstrip() + " ") + else: + thisPar.append(tTemp.rstrip() + " ") + + elif tType == self.T_SYNOPSIS and self.doSynopsis: + tmpResult.append(self._formatSynopsis(tText)) + + elif tType == self.T_COMMENT and self.doComments: + tmpResult.append(self._formatComments(tText)) + + elif tType == self.T_KEYWORD and self.doKeywords: + tmpResult.append(self._formatKeywords(tText)) + + self.theResult = "".join(tmpResult) + tmpResult = [] + + self.fullMD.append(self.theResult) + + return + + def saveMarkdown(self, savePath): + """Save the data to a plain text file file. + """ + with open(savePath, mode="w", encoding="utf8") as outFile: + theText = "".join(self.fullMD) + outFile.write(theText) + + return + + def replaceTabs(self, nSpaces=8, spaceChar=" "): + """Replace tabs with spaces. + """ + fullMD = [] + eightSpace = spaceChar*nSpaces + for aPage in self.fullMD: + fullMD.append(aPage.replace("\t", eightSpace)) + + self.fullMD = fullMD + return + + ## + # Internal Functions + ## + + def _formatSynopsis(self, tText): + """Apply Markdown formatting to synopsis. + """ + if self.genMode == self.M_NW: + return "%% Synopsis: %s\n" % tText + else: + return "**Synopsis:** %s\n" % tText + + def _formatComments(self, tText): + """Apply Markdown formatting to comments. + """ + if self.genMode == self.M_NW: + return "%% %s\n" % tText + else: + return "**Comment:** %s\n" % tText + + def _formatKeywords(self, tText): + """Apply Markdown formatting to keywords. + """ + isValid, theBits, thePos = self.theParent.theIndex.scanThis("@"+tText) + if not isValid or not theBits: + return "" + + retText = "" + if theBits[0] in nwLabels.KEY_NAME: + if self.genMode == self.M_NW: + retText += "@%s: " % theBits[0] + else: + retText += "**%s:** " % nwLabels.KEY_NAME[theBits[0]] + + if len(theBits) > 1: + retText += ", ".join(theBits[1:]) + + return retText + +# END Class ToMarkdown