manuskript/manuskript/exporter/pandoc/abstractPlainText.py
TheJackiMonster a33249fc9d
Added guard to catch errors with translation
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
2022-05-17 11:43:22 +02:00

407 lines
16 KiB
Python

#!/usr/bin/env python
# --!-- coding: utf8 --!--
import re
from PyQt5.QtGui import QTextCharFormat, QFont
from PyQt5.QtWidgets import qApp, QVBoxLayout, QCheckBox, QWidget, QHBoxLayout, QLabel, QSpinBox, QComboBox
from manuskript.exporter.manuskript.markdown import markdown, markdownSettings
from manuskript.ui.collapsibleGroupBox2 import collapsibleGroupBox2
from manuskript.functions import safeTranslate
import logging
LOGGER = logging.getLogger(__name__)
class abstractPlainText(markdown):
name = "SUBCLASSME"
description = "SUBCLASSME"
exportVarName = "SUBCLASSME"
toFormat = "SUBCLASSME"
icon = "SUBCLASSME"
exportFilter = "SUBCLASSME"
exportDefaultSuffix = ".SUBCLASSME"
def __init__(self, exporter):
self.exporter = exporter
def settingsWidget(self):
# Get pandoc major version to determine valid command line options
p = re.compile(r'pandoc (\d+)\.(\d+).*')
m = p.match(self.exporter.version())
if m:
majorVersion = m.group(1)
minorVersion = m.group(2)
else:
majorVersion = ""
minorVersion = ""
w = pandocSettings(self, majorVersion, minorVersion, toFormat=self.toFormat)
w.loadSettings()
return w
def src(self, settingsWidget):
return markdown.output(self, settingsWidget)
def output(self, settingsWidget, outputfile=None):
args = settingsWidget.runnableSettings()
src = self.src(settingsWidget)
return self.exporter.convert(src, args, outputfile)
def preview(self, settingsWidget, previewWidget):
settings = settingsWidget.getSettings()
# Save settings
settingsWidget.writeSettings()
# Prepares text edit
self.preparesTextEditViewMarkdown(previewWidget, settingsWidget.settings)
self.preparesTextEditView(previewWidget, settings["Preview"]["PreviewFont"])
r = self.output(settingsWidget)
previewWidget.setPlainText(r)
def versionAsInt(version):
if version is None:
return 0
try:
return int(version)
except ValueError:
return 0
def versionToIntArray(version):
if version is None:
return [0, 0]
p = re.compile(r'(\d+)\.(\d+).*')
m = p.match(version)
if m:
majorVersion = m.group(1)
minorVersion = m.group(2)
else:
majorVersion = ""
minorVersion = ""
return [ versionAsInt(majorVersion), versionAsInt(minorVersion) ]
class pandocSetting:
def __init__(self, arg, type, format, label, widget=None, default=None, min=None, max=None, vals=None, suffix="",
minVersion=None, maxVersion=None, specific=False, toc=False):
self.arg = arg # start with EXT for extensions
self.type = type
self.label = label
self.formats = format
if "html" in self.formats:
self.formats += " slidy dzslides revealjs slideous s5 html5"
self.widget = widget
self.default = default
self.min = min
self.max = max
self.vals = vals.split("|") if vals else []
self.suffix = suffix
self.minVersion = versionToIntArray(minVersion)
self.maxVersion = versionToIntArray(maxVersion)
self.specific = specific
self.toc = toc
def isValid(self, format):
"""Return whether the specific setting is active with the given format."""
# Empty formats means all
if self.formats == "":
return True
# "html" in "html markdown latex"
elif format in self.formats:
return True
# "markdown_strict" in "html markdown latex"
elif [f for f in self.formats.split(" ") if format in f]:
return True
return False
def isCompatible(self, majorVersion, minorVersion):
majorNumber = versionAsInt(majorVersion)
minorNumber = versionAsInt(minorVersion)
if (majorNumber < self.minVersion[0]) or ((majorNumber == self.minVersion[0]) and
(minorNumber < self.minVersion[1])):
return False
if (self.maxVersion[0] == 0) and (self.maxVersion[1] == 0):
return True
return (majorNumber < self.maxVersion[0]) or ((majorNumber == self.maxVersion[0]) and
(minorNumber <= self.maxVersion[1]))
def isSpecific(self):
return self.specific
def isTOC(self):
return self.toc
class pandocSettings(markdownSettings):
settingsList = {
# General
"standalone": pandocSetting("--standalone", "checkbox", "",
safeTranslate(qApp, "Export", "Standalone document (not just a fragment)"),
default=True),
"TOC": pandocSetting("--toc", "checkbox", "",
safeTranslate(qApp, "Export", "Include a table of contents."), toc=True),
"TOC-depth": pandocSetting("--toc-depth=", "number", "",
safeTranslate(qApp, "Export", "Number of sections level to include in TOC: "),
default=3, min=1, max=6, toc=True, minVersion="1.10"),
# pandoc v1 only
"smart": pandocSetting("--smart", "checkbox", "",
safeTranslate(qApp, "Export", "Typographically correct output"),
maxVersion="1.19.2.4"),
# pandoc v1 only
"normalize": pandocSetting("--normalize", "checkbox", "",
safeTranslate(qApp, "Export", "Normalize the document (cleaner)"),
minVersion="1.8", maxVersion="1.19.2.4"),
# pandoc v1.5 to 2.7.3
"base-header": pandocSetting("--base-header-level=", "number", "",
safeTranslate(qApp, "Export", "Specify the base level for headers: "),
default=1, min=1, minVersion="1.5", maxVersion="2.7.3"),
# pandoc v2.8+
"shift-heading": pandocSetting("--shift-heading-level-by=", "number", "",
safeTranslate(qApp, "Export", "Specify the base level for headers: "),
default=0, min=0, minVersion="2.8"),
"disable-YAML": pandocSetting("EXT-yaml_metadata_block", "checkbox", "",
safeTranslate(qApp, "Export", "Disable YAML metadata block.\nUse that if you get YAML related error."),
minVersion="1.12"),
"hard-line-breaks": pandocSetting("EXT-hard_line_block", "checkbox", "",
safeTranslate(qApp, "Export", "Enable the support on markdown for line break on new line."),
minVersion="1.16"),
# Specific
"ref-link": pandocSetting("--reference-links", "checkbox", "markdown rst",
safeTranslate(qApp, "Export", "Use reference-style links instead of inline links"),
specific=True),
# pandoc v1.9 to v2.11.1
"atx": pandocSetting("--atx-headers", "checkbox", "markdown asciidoc",
safeTranslate(qApp, "Export", "Use ATX-style headers"), specific=True,
minVersion="1.9", maxVersion="2.11.1"),
# pandoc v2.11.2+
"atx-heading": pandocSetting("--markdown-headings=atx|setext", "checkbox", "markdown asciidoc",
safeTranslate(qApp, "Export", "Use ATX-style headers"), specific=True,
minVersion="2.11.2"),
"self-contained": pandocSetting("--self-contained", "checkbox", "html",
safeTranslate(qApp, "Export", "Self-contained HTML files, with no dependencies"),
specific=True, minVersion="1.9"),
"q-tags": pandocSetting("--html-q-tags", "checkbox", "html",
safeTranslate(qApp, "Export", "Use <q> tags for quotes in HTML"), specific=True,
minVersion="1.10"),
# pandoc v1 only
"latex-engine": pandocSetting("--latex-engine=", "combo", "pdf",
safeTranslate(qApp, "Export", "LaTeX engine used to produce the PDF."),
vals="pdflatex|lualatex|xelatex", specific=True,
minVersion="1.9", maxVersion="1.19.2.4"),
# pandoc v2
"pdf-engine": pandocSetting("--pdf-engine=", "combo", "pdf",
safeTranslate(qApp, "Export", "LaTeX engine used to produce the PDF."),
vals="pdflatex|lualatex|xelatex", minVersion="2.0", specific=True),
"epub3": pandocSetting("EXTepub3", "checkbox", "epub",
safeTranslate(qApp, "Export", "Convert to ePUB3"), specific=True,
minVersion="1.10"),
# PDF
"latex-ps": pandocSetting("--variable=papersize:", "combo", "pdf latex", # FIXME: does not work with default template
safeTranslate(qApp, "Export", "Paper size:"),
vals="letter|A4|A5", specific=True, minVersion="1.4"),
"latex-fs": pandocSetting("--variable=fontsize:", "number", "pdf latex", # FIXME: does not work with default template
safeTranslate(qApp, "Export", "Font size:"),
min=8, max=88, default=12, suffix="pt", specific=True, minVersion="1.4"),
"latex-class": pandocSetting("--variable=documentclass:", "combo", "pdf latex",
safeTranslate(qApp, "Export", "Class:"),
vals="article|report|book|memoir", specific=True, minVersion="1.4"),
"latex-ls": pandocSetting("--variable=linestretch:", "combo", "pdf latex",
safeTranslate(qApp, "Export", "Line spacing:"),
vals="1|1.25|1.5|2", specific=True, minVersion="1.4"),
# FIXME: complete with http://pandoc.org/README.html#variables-for-latex
}
def __init__(self, _format, majorVersion="", minorVersion="", toFormat=None, parent=None):
markdownSettings.__init__(self, _format, parent)
self.format = toFormat
self.majorVersion = majorVersion
self.minorVersion = minorVersion
dropSettings = []
for key, setting in self.settingsList.items():
if not setting.isCompatible(self.majorVersion, self.minorVersion):
dropSettings.append(key)
LOGGER.info(f'Using pandoc settings: {self.majorVersion}.{self.minorVersion}, dropping: {dropSettings}')
for key in dropSettings:
self.settingsList.pop(key, None)
w = QWidget(self)
w.setLayout(QVBoxLayout())
self.grpPandocGeneral = self.collapsibleGroupBox(self.tr("General"), w)
self.grpPandocSpecific = self.collapsibleGroupBox(self.tr("Custom settings for {}").format(self.format), w)
self.grpPandocTOC = self.collapsibleGroupBox(self.tr("Table of Content"), w)
for key, setting in self.settingsList.items():
if setting.isTOC():
self.addSettingsWidget(key, self.grpPandocTOC)
elif setting.isSpecific():
self.addSettingsWidget(key, self.grpPandocSpecific)
else:
self.addSettingsWidget(key, self.grpPandocGeneral)
self.toolBox.insertItem(self.toolBox.count() - 1, w, "Pandoc")
self.toolBox.layout().setSpacing(0) # Not sure why this is needed, but hey...
self.getSettings()
def collapsibleGroupBox(self, title, parent):
g = collapsibleGroupBox2(title=title)
parent.layout().addWidget(g)
g.setLayout(QVBoxLayout())
return g
def addSettingsWidget(self, settingsName, parent):
if not settingsName in self.settingsList:
return
s = self.settingsList[settingsName]
if not s.isValid(self.format):
# That setting is not available for that export format
return
if "checkbox" in s.type:
s.widget = QCheckBox(s.label)
if s.default:
s.widget.setChecked(True)
parent.layout().addWidget(s.widget)
elif "number" in s.type:
l = QHBoxLayout()
label = QLabel(s.label, parent)
label.setWordWrap(True)
l.addWidget(label, 8)
s.widget = QSpinBox()
s.widget.setValue(s.default if s.default else 0)
if s.min:
s.widget.setMinimum(s.min)
if s.max:
s.widget.setMaximum(s.max)
if s.suffix:
s.widget.setSuffix(s.suffix)
l.addWidget(s.widget, 2)
parent.layout().addLayout(l)
elif "combo" in s.type:
l = QHBoxLayout()
label = QLabel(s.label, parent)
label.setWordWrap(True)
l.addWidget(label, 6)
s.widget = QComboBox()
s.widget.addItems(s.vals)
l.addWidget(s.widget, 2)
parent.layout().addLayout(l)
def updateFromSettings(self):
markdownSettings.updateFromSettings(self)
# s = self.settings["Preview"]
# val = s.get("MarkdownHighlighter", False)
# self.chkMarkdownHighlighter.setChecked(val)
if not "Pandoc" in self.settings:
return
for name in self.settingsList:
s = self.settingsList[name]
if s.isValid(self.format):
if s.type == "checkbox" and name in self.settings["Pandoc"]:
s.widget.setChecked(self.settings["Pandoc"][name])
elif s.type == "number" and name in self.settings["Pandoc"]:
s.widget.setValue(int(self.settings["Pandoc"][name]))
elif s.type == "combo" and name in self.settings["Pandoc"]:
s.widget.setCurrentText(self.settings["Pandoc"][name])
def getSettings(self):
self.settings = markdownSettings.getSettings(self)
P = self.settings.get("Pandoc", {})
for name in self.settingsList:
s = self.settingsList[name]
if s.isValid(self.format):
if s.type == "checkbox":
P[name] = s.widget.isChecked()
elif s.type == "number":
P[name] = str(s.widget.value())
elif s.type == "combo":
P[name] = s.widget.currentText()
self.settings["Pandoc"] = P
return self.settings
def runnableSettings(self):
# First we get extensions (where arg starts with EXT)
extensions = ""
toFormat = self.format
for name in self.settingsList:
s = self.settingsList[name]
if s.arg[:3] == "EXT" and s.isValid(self.format):
if name == "disable-YAML" and s.widget.isChecked():
extensions += "-yaml_metadata_block"
if name == "epub3" and s.widget.isChecked():
toFormat = "epub3"
if name == "hard-line-breaks" and s.widget.isChecked():
extensions += "+hard_line_breaks"
r = ["--from=markdown" + extensions,
"--to={}".format(toFormat)]
# Add every command
for name in self.settingsList:
s = self.settingsList[name]
if s.arg[:3] == "EXT":
continue
if s.isValid(self.format):
rr = ""
if s.type == "checkbox":
if s.widget.isChecked():
rr = s.arg
elif s.type == "number":
rr = "{}{}".format(
s.arg,
str(s.widget.value())
)
elif s.type == "combo":
rr = "{}{}".format(
s.arg,
s.widget.currentText()
)
if rr:
r.append(rr+s.suffix)
return r