Add a new RST role :ffdoc: to insert the generated RST markup for a formatter function

Needs testing to ensure that it works when called in contexts likea
bulleted list, not sure how well the generated markup works when place
after a bullet.
This commit is contained in:
Kovid Goyal 2024-11-11 10:29:39 +05:30
parent 8c2fadc33e
commit 6458b10f4b
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 33 additions and 5 deletions

View File

@ -4,13 +4,15 @@
import os import os
import re import re
from functools import partial from functools import lru_cache, partial
from tempfile import TemporaryDirectory
from calibre.linux import cli_index_strings, entry_points
from epub import EPUBHelpBuilder from epub import EPUBHelpBuilder
from sphinx.util.console import bold from sphinx.util.console import bold
from sphinx.util.logging import getLogger from sphinx.util.logging import getLogger
from calibre.linux import cli_index_strings, entry_points
def info(*a): def info(*a):
getLogger(__name__).info(*a) getLogger(__name__).info(*a)
@ -19,10 +21,36 @@ def info(*a):
include_pat = re.compile(r'^.. include:: (\S+.rst)', re.M) include_pat = re.compile(r'^.. include:: (\S+.rst)', re.M)
@lru_cache(2)
def formatter_funcs():
from calibre.db.legacy import LibraryDatabase
from calibre.utils.ffml_processor import FFMLProcessor
from calibre.utils.formatter_functions import formatter_functions
ans = {}
with TemporaryDirectory() as tdir:
db = LibraryDatabase(tdir) # needed to load formatter_funcs
ffml = FFMLProcessor()
all_funcs = formatter_functions().get_builtins()
for func_name, func in all_funcs.items():
ans[func_name] = ffml.document_to_rst(func.doc, func_name)
db.close()
del db
return ans
def ffdoc(m):
func_name = m.group(1)
return formatter_funcs()[func_name]
def source_read_handler(app, docname, source): def source_read_handler(app, docname, source):
src = source[0] src = source[0]
if app.builder.name != 'gettext' and app.config.language != 'en': if app.builder.name != 'gettext':
src = re.sub(r'(\s+generated/)en/', r'\1' + app.config.language + '/', src) if app.config.language != 'en':
src = re.sub(r'(\s+generated/)en/', r'\1' + app.config.language + '/', src)
if docname == 'template_lang':
src = re.sub(r':ffdoc:`(.+?)`', ffdoc, src)
# Sphinx does not call source_read_handle for the .. include directive # Sphinx does not call source_read_handle for the .. include directive
for m in reversed(tuple(include_pat.finditer(src))): for m in reversed(tuple(include_pat.finditer(src))):
included_doc_name = m.group(1).lstrip('/') included_doc_name = m.group(1).lstrip('/')

View File

@ -173,7 +173,7 @@ In the function documentation below, the notation ``[something]*`` means that ``
The functions intended for use in Single Function Mode are: The functions intended for use in Single Function Mode are:
* ``capitalize()`` -- returns the value with the first letter upper case and the rest lower case. * :ffdoc:`capitalize`
* ``contains(pattern, text if match, text if not match)`` -- checks if the value is matched by the regular expression ``pattern``. Returns ``text if match`` if the pattern matches the value, otherwise returns ``text if no match``. * ``contains(pattern, text if match, text if not match)`` -- checks if the value is matched by the regular expression ``pattern``. Returns ``text if match`` if the pattern matches the value, otherwise returns ``text if no match``.
* ``count(separator)`` -- interprets the value as a list of items separated by ``separator`` and returns the number of items in the list. Most lists use a comma as the separator, but ``authors`` uses an ampersand (&). Examples: ``{tags:count(,)}``, ``{authors:count(&)}``. Aliases: ``count()``, ``list_count()`` * ``count(separator)`` -- interprets the value as a list of items separated by ``separator`` and returns the number of items in the list. Most lists use a comma as the separator, but ``authors`` uses an ampersand (&). Examples: ``{tags:count(,)}``, ``{authors:count(&)}``. Aliases: ``count()``, ``list_count()``
* ``format_number(template)`` -- interprets the value as a number and formats that number using a Python formatting template such as ``{0:5.2f}`` or ``{0:,d}`` or ``${0:5,.2f}``. The formatting template must begin with ``{0:`` and end with ``}`` as in the above examples. Exception: you can leave off the leading "{0:" and trailing "}" if the format template contains only a format. See the template language and the `Python documentation <https://docs.python.org/3/library/string.html#formatstrings>`_ for more examples. Returns the empty string if formatting fails. * ``format_number(template)`` -- interprets the value as a number and formats that number using a Python formatting template such as ``{0:5.2f}`` or ``{0:,d}`` or ``${0:5,.2f}``. The formatting template must begin with ``{0:`` and end with ``}`` as in the above examples. Exception: you can leave off the leading "{0:" and trailing "}" if the format template contains only a format. See the template language and the `Python documentation <https://docs.python.org/3/library/string.html#formatstrings>`_ for more examples. Returns the empty string if formatting fails.