diff --git a/src/calibre/gui2/dialogs/ff_doc_editor.py b/src/calibre/gui2/dialogs/ff_doc_editor.py
index 867e68129f..99da008172 100644
--- a/src/calibre/gui2/dialogs/ff_doc_editor.py
+++ b/src/calibre/gui2/dialogs/ff_doc_editor.py
@@ -149,13 +149,13 @@ class FFDocEditor(Dialog):
try:
self.editable_text_result.setHtml(
self.ffml.document_to_html(doc.format_again(
- self.editable_text_widget.toPlainText()), 'edited text'))
+ self.editable_text_widget.toPlainText()), 'edited text', safe=False))
except Exception as e:
self.editable_text_result.setHtml(str(e))
else:
try:
self.editable_text_result.setHtml(
- self.ffml.document_to_html(self.editable_text_widget.toPlainText(), 'edited text'))
+ self.ffml.document_to_html(self.editable_text_widget.toPlainText(), 'edited text', safe=False))
except Exception as e:
self.editable_text_result.setHtml(str(e))
diff --git a/src/calibre/gui2/dialogs/template_dialog.py b/src/calibre/gui2/dialogs/template_dialog.py
index 5e35c1e453..b1afb12ad9 100644
--- a/src/calibre/gui2/dialogs/template_dialog.py
+++ b/src/calibre/gui2/dialogs/template_dialog.py
@@ -53,7 +53,7 @@ from calibre.gui2.widgets2 import Dialog, HTMLDisplay
from calibre.library.coloring import color_row_key, displayable_columns
from calibre.utils.config_base import tweaks
from calibre.utils.date import DEFAULT_DATE
-from calibre.utils.ffml_processor import FFMLProcessor
+from calibre.utils.ffml_processor import FFMLProcessor, MARKUP_ERROR
from calibre.utils.formatter import PythonTemplateContext, StopException
from calibre.utils.formatter_functions import StoredObjectType, formatter_functions
from calibre.utils.icu import lower as icu_lower
@@ -62,29 +62,6 @@ from calibre.utils.localization import localize_user_manual_link, ngettext
from calibre.utils.resources import get_path as P
-def safe_get_doc_html(ffml, func, fname, original_doc):
- def build_error_msg(msg):
- return 'MalformedDoc: '+msg+''
-
- # try with the original doc
- try:
- return ffml.document_to_html(original_doc, fname).strip()
- except Exception as ex:
- error_msg = build_error_msg(str(ex))
-
- # try with english doc
- doc = getattr(func, 'doc', '')
- doc = getattr(doc, 'formatted_english', doc)
- try:
- rslt = ffml.document_to_html(doc, fname).strip()
- return error_msg+'
'+ rslt
- except Exception as ex:
- error_msg = build_error_msg(str(ex))
-
- # return raw doc
- return error_msg+'
'+doc.strip().replace('\n', '
')
-
-
class DocViewer(Dialog):
def __init__(self, ffml, builtins, function_type_string_method, parent=None):
@@ -163,13 +140,9 @@ class DocViewer(Dialog):
return f'\n
{tree.escaped_text().rstrip()}
'
elif tree.node_kind() == NodeKinds.END_SUMMARY:
pass
+ elif tree.node_kind() == NodeKinds.ERROR_TEXT:
+ result += f'{tree.escaped_text()}'
elif tree.node_kind() == NodeKinds.GUI_LABEL:
result += f'{tree.escaped_text()}'
elif tree.node_kind() == NodeKinds.ITALIC_TEXT:
@@ -259,7 +320,7 @@ class FFMLProcessor:
result += self.tree_to_html(child, depth=depth+1)
return result
- def document_to_html(self, document, name):
+ def document_to_html(self, document, name, safe=True):
"""
Given a document in the Formatter Function Markup Language (FFML), return
that document in HTML format.
@@ -267,14 +328,16 @@ class FFMLProcessor:
:param document: the text in FFML.
:param name: the name of the document, used during error
processing. It is usually the name of the function.
+ :param safe: if true, do not propagate exceptions. Instead attempt to
+ recover using the English version as well as display an error.
:return: a string containing the HTML
"""
- tree = self.parse_document(document, name)
+ tree = self.parse_document(document, name, safe=safe)
return self.tree_to_html(tree, 0)
- def document_to_summary_html(self, document, name):
+ def document_to_summary_html(self, document, name, safe=True):
"""
Given a document in the Formatter Function Markup Language (FFML), return
that document's summary in HTML format.
@@ -282,6 +345,8 @@ class FFMLProcessor:
:param document: the text in FFML.
:param name: the name of the document, used during error
processing. It is usually the name of the function.
+ :param safe: if true, do not propagate exceptions. Instead attempt to
+ recover using the English version as well as display an error.
:return: a string containing the HTML
@@ -291,7 +356,7 @@ class FFMLProcessor:
if sum_tag > 0:
document = document[0:sum_tag]
fname = document[0:document.find('(')].lstrip('`')
- tree = self.parse_document(document, name)
+ tree = self.parse_document(document, name, safe=safe)
result = self.tree_to_html(tree, depth=0)
paren = result.find('(')
result = f'{fname}{result[paren:]}'
@@ -337,6 +402,8 @@ class FFMLProcessor:
indent_text(f'``{tree.text()}``')
elif tree.node_kind() == NodeKinds.END_SUMMARY:
pass
+ elif tree.node_kind() == NodeKinds.ERROR_TEXT:
+ indent_text(f'**{tree.text()}**')
elif tree.node_kind() == NodeKinds.GUI_LABEL:
indent_text(f':guilabel:`{tree.text()}`')
elif tree.node_kind() == NodeKinds.ITALIC_TEXT:
@@ -361,7 +428,7 @@ class FFMLProcessor:
result = self.tree_to_rst(child, indent, result=result)
return result
- def document_to_rst(self, document, name, indent=0, prefix=None):
+ def document_to_rst(self, document, name, indent=0, prefix=None, safe=True):
"""
Given a document in the Formatter Function Markup Language (FFML), return
that document in RST (sphinx reStructuredText) format.
@@ -375,16 +442,18 @@ class FFMLProcessor:
:param prefix: string. if supplied, this string replaces the indent
on the first line of the output. This permits specifying
an RST block, for example a bullet list
+ :param safe: if true, do not propagate exceptions. Instead attempt to
+ recover using the English version as well as display an error.
:return: a string containing the RST text
"""
- doc = self.tree_to_rst(self.parse_document(document, name), indent)
+ doc = self.tree_to_rst(self.parse_document(document, name, safe=safe), indent)
if prefix is not None:
doc = prefix + doc.lstrip(' ' * indent)
return doc
- def document_to_summary_rst(self, document, name, indent=0, prefix=None):
+ def document_to_summary_rst(self, document, name, indent=0, prefix=None, safe=True):
"""
Given a document in the Formatter Function Markup Language (FFML), return
that document's summary in RST (sphinx reStructuredText) format.
@@ -398,6 +467,8 @@ class FFMLProcessor:
:param prefix: string. if supplied, this string replaces the indent
on the first line of the output. This permits specifying
an RST block, for example a bullet list
+ :param safe: if true, do not propagate exceptions. Instead attempt to
+ recover using the English version as well as display an error.
:return: a string containing the RST text
@@ -407,7 +478,7 @@ class FFMLProcessor:
if sum_tag > 0:
document = document[0:sum_tag]
fname = document[0:document.find('(')].lstrip('`')
- doc = self.tree_to_rst(self.parse_document(document, name), indent)
+ doc = self.tree_to_rst(self.parse_document(document, name, safe=safe), indent)
lparen = doc.find('(')
doc = f':ref:`ff_{fname}`\\ ``{doc[lparen:]}'
if prefix is not None: