or
.
- RST output is not indented.
-
API example: generate documents for all builtin formatter functions
--------------------
from calibre.utils.ffml_processor import FFMLProcessor
@@ -253,18 +268,16 @@ class FFMLProcessor:
result = ''
if tree.node_kind() == NodeKinds.TEXT:
result += 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()}
'
- elif tree.node_kind() == NodeKinds.ITALIC_TEXT:
- result += f'
{tree.escaped_text()}'
elif tree.node_kind() == NodeKinds.GUI_LABEL:
result += f'
{tree.escaped_text()}'
- elif tree.node_kind() == NodeKinds.BLANK_LINE:
- result += '\n
\n
\n'
- elif tree.node_kind() == NodeKinds.URL:
- result += f'
{tree.escaped_label()}'
+ elif tree.node_kind() == NodeKinds.ITALIC_TEXT:
+ result += f'
{tree.escaped_text()}'
elif tree.node_kind() == NodeKinds.LIST:
result += '\n
\n'
for child in tree.children():
@@ -272,6 +285,10 @@ class FFMLProcessor:
result += self.tree_to_html(child, depth+1)
result += '\n'
result += '
\n'
+ elif tree.node_kind() == NodeKinds.REF:
+ result += f'
{tree.escaped_text()}()
'
+ elif tree.node_kind() == NodeKinds.URL:
+ result += f'
{tree.escaped_label()}'
elif tree.node_kind() in (NodeKinds.DOCUMENT, NodeKinds.LIST_ITEM):
for child in tree.children():
result += self.tree_to_html(child, depth+1)
@@ -306,29 +323,20 @@ class FFMLProcessor:
"""
if result is None:
result = ' ' * indent
- if tree.node_kind() == NodeKinds.TEXT:
- txt = tree.text()
- if not result:
- txt = txt.lstrip()
- elif result.endswith('\n'):
- txt = txt.lstrip()
- result += ' ' * indent
- result += txt
- elif tree.node_kind() == NodeKinds.CODE_TEXT:
- result += f'``{tree.text()}``'
- elif tree.node_kind() == NodeKinds.GUI_LABEL:
- result += f':guilabel:`{tree.text()}`'
+
+ if tree.node_kind() == NodeKinds.BLANK_LINE:
+ result += '\n\n'
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.BLANK_LINE:
- result += '\n\n'
+ elif tree.node_kind() == NodeKinds.CODE_TEXT:
+ result += f'``{tree.text()}``'
+ elif tree.node_kind() == NodeKinds.GUI_LABEL:
+ result += f':guilabel:`{tree.text()}`'
elif tree.node_kind() == NodeKinds.ITALIC_TEXT:
result += f'`{tree.text()}`'
- elif tree.node_kind() == NodeKinds.URL:
- result += f'`{tree.label()} <{tree.url()}>`_'
elif tree.node_kind() == NodeKinds.LIST:
result += '\n\n'
for child in tree.children():
@@ -336,6 +344,18 @@ class FFMLProcessor:
result = self.tree_to_rst(child, indent+1, result)
result += '\n'
result += '\n'
+ elif tree.node_kind() == NodeKinds.REF:
+ result += f':ref:`{tree.text()}()
`'
+ elif tree.node_kind() == NodeKinds.TEXT:
+ txt = tree.text()
+ if not result:
+ txt = txt.lstrip()
+ elif result.endswith('\n'):
+ txt = txt.lstrip()
+ result += ' ' * indent
+ result += txt
+ elif tree.node_kind() == NodeKinds.URL:
+ result += f'`{tree.label()} <{tree.url()}>`_'
elif tree.node_kind() in (NodeKinds.DOCUMENT, NodeKinds.LIST_ITEM):
for child in tree.children():
result = self.tree_to_rst(child, indent, result)
@@ -368,11 +388,12 @@ class FFMLProcessor:
keywords = {'``': NodeKinds.CODE_TEXT, # must be before '`'
'`': NodeKinds.ITALIC_TEXT,
- ':guilabel:': NodeKinds.GUI_LABEL,
'[CODE]': NodeKinds.CODE_BLOCK,
- '[URL': NodeKinds.URL,
+ ':guilabel:': NodeKinds.GUI_LABEL,
'[LIST]': NodeKinds.LIST,
'[/LIST]': NodeKinds.END_LIST,
+ ':ref:': NodeKinds.REF,
+ '[URL': NodeKinds.URL,
'[*]': NodeKinds.LIST_ITEM,
'\n\n': NodeKinds.BLANK_LINE
}
@@ -426,6 +447,17 @@ class FFMLProcessor:
return min(positions)
return len(self.input)
+ def get_code_block(self):
+ self.move_pos(len('[CODE]\n'))
+ end = self.find('[/CODE]')
+ if end < 0:
+ self.error('Missing [/CODE] for block')
+ node = CodeBlock(self.text_to(end))
+ self.move_pos(end + len('[/CODE]'))
+ if self.text_to(1) == '\n':
+ self.move_pos(1)
+ return node
+
def get_code_text(self):
self.move_pos(len('``'))
end = self.find('``')
@@ -435,15 +467,6 @@ class FFMLProcessor:
self.move_pos(end + len('``'))
return node
- def get_italic_text(self):
- self.move_pos(1)
- end = self.find('`')
- if end < 0:
- self.error('Missing closing "`" for italics')
- node = ItalicTextNode(self.text_to(end))
- self.move_pos(end + 1)
- return node
-
def get_gui_label(self):
self.move_pos(len(':guilabel:`'))
end = self.find('`')
@@ -453,15 +476,13 @@ class FFMLProcessor:
self.move_pos(end + len('`'))
return node
- def get_code_block(self):
- self.move_pos(len('[CODE]\n'))
- end = self.find('[/CODE]')
+ def get_italic_text(self):
+ self.move_pos(1)
+ end = self.find('`')
if end < 0:
- self.error('Missing [/CODE] for block')
- node = CodeBlock(self.text_to(end))
- self.move_pos(end + len('[/CODE]'))
- if self.text_to(1) == '\n':
- self.move_pos(1)
+ self.error('Missing closing "`" for italics')
+ node = ItalicTextNode(self.text_to(end))
+ self.move_pos(end + 1)
return node
def get_list(self):
@@ -480,6 +501,15 @@ class FFMLProcessor:
self.move_pos(1)
return list_node
+ def get_ref(self):
+ self.move_pos(len(':ref:`'))
+ end = self.find('`')
+ if end < 0:
+ self.error('Missing ` (backquote) for :ref:')
+ node = RefNode(self.text_to_no_newline(end, 'REF (:ref:`)'))
+ self.move_pos(end + len('`'))
+ return node
+
def get_url(self):
self.move_pos(len('[URL'))
hp = self.find('href="')
@@ -507,27 +537,29 @@ class FFMLProcessor:
txt = self.text_to(p).replace('\n', ' ')
parent.add_child(TextNode(txt))
self.move_pos(p)
+ elif p == NodeKinds.BLANK_LINE:
+ parent.add_child(BlankLineNode())
+ self.move_pos(2)
elif p == NodeKinds.CODE_TEXT:
parent.add_child(self.get_code_text())
elif p == NodeKinds.CODE_BLOCK:
parent.add_child(self.get_code_block())
+ elif p == NodeKinds.GUI_LABEL:
+ parent.add_child(self.get_gui_label())
+ elif p == NodeKinds.ITALIC_TEXT:
+ parent.add_child(self.get_italic_text())
elif p == NodeKinds.LIST:
parent.add_child(self.get_list())
elif p == NodeKinds.LIST_ITEM:
return parent
elif p == NodeKinds.END_LIST:
return parent
- elif p == NodeKinds.BLANK_LINE:
- parent.add_child(BlankLineNode())
- self.move_pos(2)
- elif p == NodeKinds.ITALIC_TEXT:
- parent.add_child(self.get_italic_text())
- elif p == NodeKinds.GUI_LABEL:
- parent.add_child(self.get_gui_label())
+ elif p == NodeKinds.REF:
+ parent.add_child(self.get_ref())
elif p == NodeKinds.URL:
parent.add_child(self.get_url())
else:
- self.move_pos(p+1)
+ self.error(f'Fatal parse error with node type {p}')
if self.at_end():
break
return parent