diff --git a/manual/custom.py b/manual/custom.py index aaec02e502..6a2327db4c 100644 --- a/manual/custom.py +++ b/manual/custom.py @@ -4,13 +4,15 @@ import os 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 sphinx.util.console import bold from sphinx.util.logging import getLogger +from calibre.linux import cli_index_strings, entry_points + def info(*a): getLogger(__name__).info(*a) @@ -19,10 +21,36 @@ def info(*a): 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): src = source[0] - if app.builder.name != 'gettext' and app.config.language != 'en': - src = re.sub(r'(\s+generated/)en/', r'\1' + app.config.language + '/', src) + if app.builder.name != 'gettext': + 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 for m in reversed(tuple(include_pat.finditer(src))): included_doc_name = m.group(1).lstrip('/') diff --git a/manual/template_lang.rst b/manual/template_lang.rst index 8e1adbd30f..99f30d5b0b 100644 --- a/manual/template_lang.rst +++ b/manual/template_lang.rst @@ -173,7 +173,7 @@ In the function documentation below, the notation ``[something]*`` means that `` 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``. * ``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 `_ for more examples. Returns the empty string if formatting fails.