diff --git a/src/calibre/utils/ffml_processor.py b/src/calibre/utils/ffml_processor.py index a8fc7143c9..136e86f221 100644 --- a/src/calibre/utils/ffml_processor.py +++ b/src/calibre/utils/ffml_processor.py @@ -13,16 +13,17 @@ from calibre import prepare_string_for_xml class NodeKinds(IntEnum): DOCUMENT = -1 BLANK_LINE = -2 - CODE_TEXT = -3 - CODE_BLOCK = -4 - END_LIST = -5 - GUI_LABEL = -6 - ITALIC_TEXT = -7 - LIST = -8 - LIST_ITEM = -9 - REF = -10 - TEXT = -11 - URL = -12 + BOLD_TEXT = -3 + CODE_TEXT = -4 + CODE_BLOCK = -5 + END_LIST = -6 + GUI_LABEL = -7 + ITALIC_TEXT = -8 + LIST = -9 + LIST_ITEM = -10 + REF = -11 + TEXT = -12 + URL = -13 class Node: @@ -53,6 +54,13 @@ class BlankLineNode(Node): super().__init__(NodeKinds.BLANK_LINE) +class BoldTextNode(Node): + + def __init__(self, text): + super().__init__(NodeKinds.BOLD_TEXT) + self._text = text + + class CodeBlock(Node): def __init__(self, code_text): @@ -146,7 +154,11 @@ class FFMLProcessor: - inline program code text: surround this text with `` as in ``foo``. - - italic text: surround this text with `, as in `foo`. + - bold text: surrond this text with [B] [/B], as in [B]foo[/B]. Note: bold + italics don't work in RST. + + - italic text: surround this text with `, as in `foo`. Note: bold italics + don't work in RST. - text intended to reference a calibre GUI action. This uses RST syntax. Example: :guilabel:`Preferences->Advanced->Template functions` @@ -190,6 +202,9 @@ class FFMLProcessor: [/CODE] [/LIST] + - escaped character: precede the character with a backslash. This is useful + to escape tags. For example to make the [CODE] tag not a tag, use \[CODE]. + HTML output contains no CSS and does not start with a tag such as
.
API example: generate documents for all builtin formatter functions
@@ -228,7 +243,7 @@ class FFMLProcessor:
"""
if node.node_kind() in (NodeKinds.TEXT, NodeKinds.CODE_TEXT,
NodeKinds.CODE_BLOCK, NodeKinds.ITALIC_TEXT,
- NodeKinds.GUI_LABEL):
+ NodeKinds.GUI_LABEL, NodeKinds.BOLD_TEXT):
print(f'{" " * indent}{node.node_kind().name}:{node.text()}')
elif node.node_kind() == NodeKinds.URL:
print(f'{" " * indent}URL: label={node.label()}, URL={node.url()}')
@@ -269,12 +284,14 @@ class FFMLProcessor:
result = ''
if tree.node_kind() == NodeKinds.TEXT:
result += tree.escaped_text()
+ if tree.node_kind() == NodeKinds.BOLD_TEXT:
+ result += f'{tree.escaped_text()}'
elif tree.node_kind() == NodeKinds.BLANK_LINE:
result += '\n
\n
\n'
elif tree.node_kind() == NodeKinds.CODE_TEXT:
result += f'{tree.escaped_text()}
'
elif tree.node_kind() == NodeKinds.CODE_BLOCK:
- result += f'
{tree.escaped_text()}
'
+ result += f'{tree.escaped_text().rstrip()}
'
elif tree.node_kind() == NodeKinds.GUI_LABEL:
result += f'{tree.escaped_text()}'
elif tree.node_kind() == NodeKinds.ITALIC_TEXT:
@@ -322,22 +339,34 @@ class FFMLProcessor:
:return: a string containing the RST text
"""
+
+ def indent_text(txt):
+ nonlocal result
+ if not result:
+ txt = txt.lstrip()
+ elif result.endswith('\n'):
+ txt = txt.lstrip()
+ result += ' ' * indent
+ result += txt.replace('\n', ' ' * indent)
+
if result is None:
result = ' ' * indent
if tree.node_kind() == NodeKinds.BLANK_LINE:
result += '\n\n'
+ elif tree.node_kind() == NodeKinds.BOLD_TEXT:
+ indent_text(f'**{tree.text()}**')
elif tree.node_kind() == NodeKinds.CODE_BLOCK:
result += f"\n\n{' ' * indent}::\n\n"
for line in tree.text().strip().split('\n'):
result += f"{' ' * (indent+1)}{line}\n"
result += '\n'
elif tree.node_kind() == NodeKinds.CODE_TEXT:
- result += f'``{tree.text()}``'
+ indent_text(f'``{tree.text()}``')
elif tree.node_kind() == NodeKinds.GUI_LABEL:
- result += f':guilabel:`{tree.text()}`'
+ indent_text(f':guilabel:`{tree.text()}`')
elif tree.node_kind() == NodeKinds.ITALIC_TEXT:
- result += f'`{tree.text()}`'
+ indent_text(f'`{tree.text()}`')
elif tree.node_kind() == NodeKinds.LIST:
result += '\n\n'
for child in tree.children():
@@ -348,17 +377,11 @@ class FFMLProcessor:
elif tree.node_kind() == NodeKinds.REF:
if (rname := tree.text()).endswith('()'):
rname = rname[:-2]
- result += f':ref:`{rname}()