Added export to html and markdown files

This commit is contained in:
Veronica K. B. Olsen
2019-10-19 14:59:32 +02:00
parent 24fe12f0d3
commit 16401f4c1f
7 changed files with 264 additions and 20 deletions
+57
View File
@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
"""novelWriter HTML File
novelWriter HTML File
=========================
Writes the project to a html file
File History:
Created: 2019-10-19 [0.3]
"""
import logging
import nw
from nw.convert.textfile import TextFile
from nw.convert.tohtml import ToHtml
logger = logging.getLogger(__name__)
class HtmlFile(TextFile):
def __init__(self, theProject, theParent):
TextFile.__init__(self, theProject, theParent)
self.theConv = ToHtml(self.theProject, self.theParent)
return
##
# Internal Functions
##
def _doOpenFile(self, filePath):
try:
self.outFile = open(filePath,mode="w+")
self.outFile.write("<!DOCTYPE html>\n")
self.outFile.write("<html>\n")
self.outFile.write("<head>\n")
self.outFile.write("<style>\n")
self.outFile.write(" pre {background-color: #ffff99;}\n")
self.outFile.write("</style>\n")
self.outFile.write("</head>\n")
self.outFile.write("<body>\n")
except Exception as e:
self.makeAlert(["Failed to open file.",str(e)], nwAlert.ERROR)
return False
return True
def _doCloseFile(self):
if self.outFile is not None:
self.outFile.write("</body>\n")
self.outFile.write("</html>\n")
self.outFile.close()
return True
# END Class HtmlFile
+47
View File
@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
"""novelWriter Markdown File
novelWriter Markdown File
=============================
Writes the project to a markdown file
File History:
Created: 2019-10-19 [0.3]
"""
import logging
import nw
from nw.convert.textfile import TextFile
from nw.convert.tomarkdown import ToMarkdown
logger = logging.getLogger(__name__)
class MarkdownFile(TextFile):
def __init__(self, theProject, theParent):
TextFile.__init__(self, theProject, theParent)
self.theConv = ToMarkdown(self.theProject, self.theParent)
return
##
# Internal Functions
##
def _doOpenFile(self, filePath):
try:
self.outFile = open(filePath,mode="w+")
except Exception as e:
self.makeAlert(["Failed to open file.",str(e)], nwAlert.ERROR)
return False
return True
def _doCloseFile(self):
if self.outFile is not None:
self.outFile.close()
return True
# END Class MarkdownFile
+1 -2
View File
@@ -28,7 +28,6 @@ class TextFile():
self.mainConf = nw.CONFIG
self.theProject = theProject
self.theParent = theParent
self.fileExt = "txt"
self.outFile = None
self.fileName = ""
@@ -169,7 +168,7 @@ class TextFile():
return True
def _doCloseFile(self):
"""This function closes a file, and is meant to be overloaded by the subclass for other
"""This function closes the file, and is meant to be overloaded by the subclass for other
file formats.
"""
if self.outFile is not None:
+29 -6
View File
@@ -22,7 +22,6 @@ class ToHtml(Tokenizer):
def __init__(self, theProject, theParent):
Tokenizer.__init__(self, theProject, theParent)
return
def doAutoReplace(self):
@@ -53,24 +52,48 @@ class ToHtml(Tokenizer):
thisPar = []
for tType, tText, tFormat, tAlign in self.theTokens:
aStyle = []
if tAlign == self.A_CENTRE:
aStyle.append("text-align: center;")
if len(aStyle) > 0:
hStyle = " style='%s'" % (" ".join(aStyle))
else:
hStyle = ""
if tType == self.T_EMPTY:
if len(thisPar) > 0:
self.theResult += "<p>%s</p>\n" % " ".join(thisPar)
self.theResult += "<p%s>%s</p>\n" % (hStyle," ".join(thisPar))
thisPar = []
elif tType == self.T_HEAD1:
self.theResult += "<h1>%s</h1>\n" % tText
self.theResult += "<h1%s>%s</h1>\n" % (hStyle,tText)
elif tType == self.T_HEAD2:
self.theResult += "<h2>%s</h2>\n" % tText
self.theResult += "<h2%s>%s</h2>\n" % (hStyle,tText)
elif tType == self.T_HEAD3:
self.theResult += "<h3>%s</h3>\n" % tText
print(tText)
self.theResult += "<h3%s>%s</h3>\n" % (hStyle,tText)
elif tType == self.T_HEAD4:
self.theResult += "<h4>%s</h4>\n" % tText
self.theResult += "<h4%s>%s</h4>\n" % (hStyle,tText)
elif tType == self.T_SEP:
self.theResult += "<div%s>%s</div>\n" % (hStyle,tText)
elif tType == self.T_TEXT:
tTemp = tText
for xPos, xLen, xFmt in reversed(tFormat):
tTemp = tTemp[:xPos]+htmlTags[xFmt]+tTemp[xPos+xLen:]
thisPar.append(tTemp)
elif tType == self.T_COMMENT and self.doComments:
self.theResult += "<pre>%s</pre>\n" % tText
elif tType == self.T_COMMAND and self.doCommands:
self.theResult += "<pre>%s</pre>\n" % tText
# print(self.theResult)
return
+2 -2
View File
@@ -247,7 +247,7 @@ class Tokenizer():
if self.firstScene:
self.theTokens[n] = (self.T_EMPTY,"",None,self.A_LEFT)
else:
self.theTokens[n] = (self.T_SEP,tTemp,None,self.A_LEFT)
self.theTokens[n] = (self.T_SEP,tTemp,None,self.A_CENTRE)
else:
self.theTokens[n] = (tType,tTemp,None,self.A_LEFT)
self.firstScene = False
@@ -257,7 +257,7 @@ class Tokenizer():
if tTemp == "":
self.theTokens[n] = (self.T_EMPTY,"",None,self.A_LEFT)
elif tTemp == self.fmtSection:
self.theTokens[n] = (self.T_SEP,tTemp,None,self.A_LEFT)
self.theTokens[n] = (self.T_SEP,tTemp,None,self.A_CENTRE)
else:
self.theTokens[n] = (tType,tTemp,None,self.A_LEFT)
+112
View File
@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
"""novelWriter Markdown Text Converter
novelWriter Markdown Text Converter
=======================================
Extends the Tokenizer class to write Markdown
File History:
Created: 2019-10-19 [0.3]
"""
import textwrap
import logging
import re
import nw
from nw.convert.tokenizer import Tokenizer
logger = logging.getLogger(__name__)
class ToMarkdown(Tokenizer):
def __init__(self, theProject, theParent):
Tokenizer.__init__(self, theProject, theParent)
return
def doConvert(self):
htmlTags = {
self.FMT_B_B : "**",
self.FMT_B_E : "**",
self.FMT_I_B : "_",
self.FMT_I_E : "_",
self.FMT_U_B : "__",
self.FMT_U_E : "__",
}
if self.wordWrap > 0:
tWrap = textwrap.TextWrapper(
width = self.wordWrap,
initial_indent = "",
subsequent_indent = "",
expand_tabs = True,
replace_whitespace = True,
fix_sentence_endings = False,
break_long_words = True,
drop_whitespace = True,
break_on_hyphens = True,
tabsize = 8,
max_lines = None
)
self.theResult = ""
thisPar = []
for tType, tText, tFormat, tAlign in self.theTokens:
# First check if we have a comment or plain text, as they need some
# extra replacing before we proceed to wrapping and final formatting.
if tType == self.T_COMMENT:
tText = " %s" % tText
elif tType == self.T_TEXT:
tTemp = tText
for xPos, xLen, xFmt in reversed(tFormat):
tTemp = tTemp[:xPos]+tTemp[xPos+xLen:]
tText = tTemp
tLen = len(tText)
# The text can now be word wrapped, if we have requested this and it's needed.
if self.wordWrap > 0 and tLen > self.wordWrap:
if tType == self.T_COMMENT:
tText = textwrap.fill(tText.strip(),initial_indent=" ",subsequent_indent=" ")
else:
tText = tWrap.fill(tText)
# Then the text can receive final formatting before we append it to the results.
# We also store text lines in a buffer and merge them only when we find an empty line,
# indicating a new paragraph.
if tType == self.T_EMPTY:
if len(thisPar) > 0:
self.theResult += "%s\n\n" % " ".join(thisPar)
thisPar = []
elif tType == self.T_HEAD1:
self.theResult += "# %s\n\n" % tText
elif tType == self.T_HEAD2:
self.theResult += "## %s\n\n" % tText
elif tType == self.T_HEAD3:
self.theResult += "### %s\n\n" % tText
elif tType == self.T_HEAD4:
self.theResult += "#### %s\n\n" % tText
elif tType == self.T_SEP:
self.theResult += "%s\n\n" % tText
elif tType == self.T_TEXT:
thisPar.append(tText)
elif tType == self.T_COMMENT and self.doComments:
self.theResult += "%s\n\n" % tText
elif tType == self.T_COMMAND and self.doCommands:
self.theResult += "%s\n\n" % tText
return
# END Class ToMarkdown
+16 -10
View File
@@ -24,12 +24,14 @@ from PyQt5.QtWidgets import (
QLabel, QComboBox, QLineEdit, QPushButton, QFileDialog, QProgressBar, QSpinBox
)
from nw.project.document import NWDoc
from nw.tools.translate import numberToWord
from nw.convert.textfile import TextFile
from nw.common import checkString, checkBool, checkInt
from nw.constants import nwFiles
from nw.enum import nwItemType
from nw.project.document import NWDoc
from nw.tools.translate import numberToWord
from nw.convert.textfile import TextFile
from nw.convert.htmlfile import HtmlFile
from nw.convert.markdownfile import MarkdownFile
from nw.common import checkString, checkBool, checkInt
from nw.constants import nwFiles
from nw.enum import nwItemType
logger = logging.getLogger(__name__)
@@ -121,6 +123,10 @@ class GuiExport(QDialog):
outFile = None
if eFormat == GuiExportMain.FMT_TXT:
outFile = TextFile(self.theProject, self.theParent)
elif eFormat == GuiExportMain.FMT_MD:
outFile = MarkdownFile(self.theProject, self.theParent)
elif eFormat == GuiExportMain.FMT_HTML:
outFile = HtmlFile(self.theProject, self.theParent)
if outFile is None:
return False
@@ -138,11 +144,11 @@ class GuiExport(QDialog):
self.exportStatus.setText("Failed to open file for writing ...")
return False
time.sleep(0.5)
nDone = 0
for tHandle in self.theProject.treeOrder:
time.sleep(0.1)
self.exportProgress.setValue(nDone)
tItem = self.theProject.getItem(tHandle)
@@ -338,8 +344,8 @@ class GuiExportMain(QWidget):
self.outputFormat = QComboBox(self)
self.outputFormat.addItem("Plain Text (.txt)", self.FMT_TXT)
# self.outputFormat.addItem("Markdown (.md)", self.FMT_MD)
# self.outputFormat.addItem("HTML5 (.htm)", self.FMT_HTML)
self.outputFormat.addItem("Markdown (.md)", self.FMT_MD)
self.outputFormat.addItem("HTML5 (.htm)", self.FMT_HTML)
# self.outputFormat.addItem("HTML5 for eBook (.htm)", self.FMT_EBOOK)
# self.outputFormat.addItem("Open Document (.odt)", self.FMT_ODT)
# self.outputFormat.addItem("LaTeX for PDF (.tex)", self.FMT_TEX)