mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
Add a new template function set_globals() that sets key:value pairs in the globals dict. Also slightly improve template language documentation.
This commit is contained in:
parent
5aa83f99af
commit
8fbb8df75c
@ -156,7 +156,8 @@ The functions available are listed below. Note that the definitive documentation
|
||||
* ``contains(pattern, text if match, text if not match)`` -- checks if field contains matches for the regular expression `pattern`.
|
||||
Returns `text if match` if matches are found, otherwise it returns `text if no match`.
|
||||
* ``count(separator)`` -- interprets the value as a list of items separated by `separator`, returning 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(&)}`
|
||||
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 field as a number and format that number using a Python formatting template such as
|
||||
"{0:5.2f}" or "{0:,d}" or "${0:5,.2f}". The field_name part of the template must be a 0 (zero) (the "{0:" in the above examples).
|
||||
You can leave off the leading "{0:" and trailing "}" if the template contains only a format. See the template language and Python
|
||||
@ -467,6 +468,7 @@ parameters can be statements (sequences of expressions). Note that the definitiv
|
||||
of items separated by `separator`, evaluating the `pattern` against each value in the list. If the `pattern` matches a value,
|
||||
return `found_val`, otherwise return `not_found_val`. The `pattern` and `found_value` can be repeated as many times as desired,
|
||||
permitting returning different values depending on the search. The patterns are checked in order. The first match is returned.
|
||||
Aliases: ``in_list()``, ``list_contains()``
|
||||
* ``list_difference(list1, list2, separator)`` -- return a list made by removing from `list1` any item found in `list2`,
|
||||
using a case-insensitive comparison. The items in `list1` and `list2` are separated by separator, as are the items in the returned list.
|
||||
* ``list_equals(list1, sep1, list2, sep2, yes_val, no_val)`` -- return `yes_val` if `list1` and `list2` contain the same items,
|
||||
@ -481,9 +483,10 @@ parameters can be statements (sequences of expressions). Note that the definitiv
|
||||
replacements are not optional. It uses re_group(item, search_re, template ...) when doing the replacements.
|
||||
* ``list_sort(list, direction, separator)`` -- return list sorted using a case-insensitive sort. If ``direction`` is zero, ``list`` is
|
||||
sorted ascending, otherwise descending. The list items are separated by separator, as are the items in the returned list.
|
||||
* ``list_union(list1, list2, separator)`` -- return a list made by merging the items in ``list1`` and ``list2``, removing duplicate items using
|
||||
a case-insensitive comparison. If items differ in case, the one in ``list1`` is used. The items in ``list1`` and ``list2`` are separated by
|
||||
``separator``, as are the items in the returned list.
|
||||
* ``list_union(list1, list2, separator)`` -- return a list made by merging the items in ``list1`` and ``list2``, removing
|
||||
duplicate items using a case-insensitive comparison. If items differ in case, the one in ``list1`` is used. The items
|
||||
in ``list1`` and ``list2`` are separated by ``separator``, as are the items in the returned list.
|
||||
Aliases: ``merge_lists()``, ``list_union()``
|
||||
* ``mod(x)`` -- returns the remainder of ``x / y``, where ``x``, ``y``, and the result are integers. Throws an exception if either ``x`` or
|
||||
``y`` is not a number.
|
||||
* ``multiply(x, y, ...)`` -- returns the product of its arguments. Throws an exception if any argument is not a number.
|
||||
@ -681,13 +684,19 @@ The full method signature is:
|
||||
|
||||
**Template writer: how to access the additional information**
|
||||
|
||||
You access the additional information in a template using the template function ``globals(id[=expression] [, id[=expression]]*)``
|
||||
You access the additional information (the `globals dict`) in a template using the template function
|
||||
``globals(id[=expression] [, id[=expression]]*)``
|
||||
where ``id`` is any legal variable name. This function checks whether the additional information provided by the developer
|
||||
contains the name. If it does then the function assigns the provided value to a template local variable with the given name.
|
||||
contains the name. If it does then the function assigns the provided value to a template local variable with that name.
|
||||
If the name is not in the additional information and if an ``expression`` is provided, the ``expression`` is evaluated and
|
||||
the result is assigned to the local variable. If neither a value nor an expression is provided, the function assigns
|
||||
the empty string (``''``) to the local variable.
|
||||
|
||||
A template can set a value in the globals dict using the template function
|
||||
``set_globals(id[=expression] [, id[=expression]]*)``. This function sets the globals dict key:value pair ``id:value`` where
|
||||
``value`` is the value of the template local variable ``id``. If that local variable doesn't exist then ``value`` is
|
||||
set to the result of evaluating ``expression``.
|
||||
|
||||
|
||||
Notes on the difference between modes
|
||||
-----------------------------------------
|
||||
|
@ -215,7 +215,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
||||
def __init__(self, parent, text, mi=None, fm=None, color_field=None,
|
||||
icon_field_key=None, icon_rule_kind=None, doing_emblem=False,
|
||||
text_is_placeholder=False, dialog_is_st_editor=False,
|
||||
global_vars={}, all_functions=None, builtin_functions=None):
|
||||
global_vars=None, all_functions=None, builtin_functions=None):
|
||||
QDialog.__init__(self, parent)
|
||||
Ui_TemplateDialog.__init__(self)
|
||||
self.setupUi(self)
|
||||
@ -224,7 +224,10 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
||||
self.iconing = icon_field_key is not None
|
||||
self.embleming = doing_emblem
|
||||
self.dialog_is_st_editor = dialog_is_st_editor
|
||||
self.global_vars = global_vars
|
||||
if global_vars is None:
|
||||
self.global_vars = {}
|
||||
else:
|
||||
self.global_vars = global_vars
|
||||
|
||||
cols = []
|
||||
if fm is not None:
|
||||
@ -316,7 +319,8 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
||||
self.setWindowIcon(icon)
|
||||
|
||||
self.all_functions = all_functions if all_functions else formatter_functions().get_functions()
|
||||
self.builtins = builtin_functions if builtin_functions else formatter_functions().get_builtins()
|
||||
self.builtins = (builtin_functions if builtin_functions else
|
||||
formatter_functions().get_builtins_and_aliases())
|
||||
|
||||
self.last_text = ''
|
||||
self.highlighter = TemplateHighlighter(self.textbox.document(), builtin_functions=self.builtins)
|
||||
|
@ -33,7 +33,8 @@ class Node(object):
|
||||
NODE_FIRST_NON_EMPTY = 12
|
||||
NODE_FOR = 13
|
||||
NODE_GLOBALS = 14
|
||||
NODE_CONTAINS = 15
|
||||
NODE_SET_GLOBALS = 15
|
||||
NODE_CONTAINS = 16
|
||||
|
||||
|
||||
class IfNode(Node):
|
||||
@ -92,6 +93,13 @@ class GlobalsNode(Node):
|
||||
self.expression_list = expression_list
|
||||
|
||||
|
||||
class SetGlobalsNode(Node):
|
||||
def __init__(self, expression_list):
|
||||
Node.__init__(self)
|
||||
self.node_type = self.NODE_SET_GLOBALS
|
||||
self.expression_list = expression_list
|
||||
|
||||
|
||||
class StringInfixNode(Node):
|
||||
def __init__(self, operator, left, right):
|
||||
Node.__init__(self)
|
||||
@ -447,7 +455,7 @@ class _Parser(object):
|
||||
return FirstNonEmptyNode(arguments)
|
||||
if (id_ == 'assign' and len(arguments) == 2 and arguments[0].node_type == Node.NODE_RVALUE):
|
||||
return AssignNode(arguments[0].name, arguments[1])
|
||||
if id_ == 'arguments' or id_ == 'globals':
|
||||
if id_ == 'arguments' or id_ == 'globals' or id_ == 'set_globals':
|
||||
new_args = []
|
||||
for arg in arguments:
|
||||
if arg.node_type not in (Node.NODE_ASSIGN, Node.NODE_RVALUE):
|
||||
@ -458,6 +466,8 @@ class _Parser(object):
|
||||
new_args.append(arg)
|
||||
if id_ == 'arguments':
|
||||
return ArgumentsNode(new_args)
|
||||
if id_ == 'set_globals':
|
||||
return SetGlobalsNode(new_args)
|
||||
return GlobalsNode(new_args)
|
||||
if id_ == 'contains' and len(arguments) == 4:
|
||||
return ContainsNode(arguments)
|
||||
@ -585,6 +595,12 @@ class _Interpreter(object):
|
||||
res = self.locals[arg.left] = self.global_vars.get(arg.left, self.expr(arg.right))
|
||||
return res
|
||||
|
||||
def do_node_set_globals(self, prog):
|
||||
res = ''
|
||||
for arg in prog.expression_list:
|
||||
res = self.global_vars[arg.left] = self.locals.get(arg.left, self.expr(arg.right))
|
||||
return res
|
||||
|
||||
def do_node_constant(self, prog):
|
||||
return prog.value
|
||||
|
||||
@ -668,6 +684,7 @@ class _Interpreter(object):
|
||||
Node.NODE_FIRST_NON_EMPTY:do_node_first_non_empty,
|
||||
Node.NODE_FOR: do_node_for,
|
||||
Node.NODE_GLOBALS: do_node_globals,
|
||||
Node.NODE_SET_GLOBALS: do_node_set_globals,
|
||||
Node.NODE_CONTAINS: do_node_contains,
|
||||
}
|
||||
|
||||
|
@ -628,7 +628,7 @@ class BuiltinInList(BuiltinFormatterFunction):
|
||||
'not_found_val. The pattern and found_value can be repeated as '
|
||||
'many times as desired, permitting returning different values '
|
||||
'depending on the search. The patterns are checked in order. The '
|
||||
'first match is returned.')
|
||||
'first match is returned. Aliases: in_list(), list_contains()')
|
||||
aliases = ['list_contains']
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val, sep, *args):
|
||||
@ -814,10 +814,13 @@ class BuiltinCount(BuiltinFormatterFunction):
|
||||
name = 'count'
|
||||
arg_count = 2
|
||||
category = 'List manipulation'
|
||||
aliases = ['list_count']
|
||||
|
||||
__doc__ = doc = _('count(val, separator) -- interprets the value as a list of items '
|
||||
'separated by `separator`, returning 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(&)}')
|
||||
'uses an ampersand. Examples: {tags:count(,)}, {authors:count(&)}. '
|
||||
'Aliases: count(), list_count()')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, val, sep):
|
||||
return unicode_type(len([v for v in val.split(sep) if v]))
|
||||
@ -1350,7 +1353,7 @@ class BuiltinListUnion(BuiltinFormatterFunction):
|
||||
'removing duplicate items using a case-insensitive comparison. If '
|
||||
'items differ in case, the one in list1 is used. '
|
||||
'The items in list1 and list2 are separated by separator, as are '
|
||||
'the items in the returned list.')
|
||||
'the items in the returned list. Aliases: list_union(), merge_lists()')
|
||||
aliases = ['merge_lists']
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, list1, list2, separator):
|
||||
@ -1917,6 +1920,24 @@ class BuiltinGlobals(BuiltinFormatterFunction):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class BuiltinSetGlobals(BuiltinFormatterFunction):
|
||||
name = 'set_globals'
|
||||
arg_count = -1
|
||||
category = 'other'
|
||||
__doc__ = doc = _('globals(id[=expression] [, id[=expression]]*) '
|
||||
'-- Retrieves "global variables" that can be passed into '
|
||||
'the formatter. It both declares and initializes local '
|
||||
'variables with the names of the global variables passed '
|
||||
'in. If the corresponding variable is not provided in '
|
||||
'the passed-in globals then it assigns that variable the '
|
||||
'provided default value. If there is no default value '
|
||||
'then the variable is set to the empty string.')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, *args):
|
||||
# The globals function is implemented in-line in the formatter
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class BuiltinFieldExists(BuiltinFormatterFunction):
|
||||
name = 'field_exists'
|
||||
arg_count = 1
|
||||
@ -1953,7 +1974,7 @@ _formatter_builtins = [
|
||||
BuiltinLowercase(), BuiltinMod(), BuiltinMultiply(), BuiltinNot(), BuiltinOndevice(),
|
||||
BuiltinOr(), BuiltinPrint(), BuiltinRatingToStars(), BuiltinRawField(), BuiltinRawList(),
|
||||
BuiltinRe(), BuiltinReGroup(), BuiltinRound(), BuiltinSelect(), BuiltinSeriesSort(),
|
||||
BuiltinShorten(), BuiltinStrcat(), BuiltinStrcatMax(),
|
||||
BuiltinSetGlobals(), BuiltinShorten(), BuiltinStrcat(), BuiltinStrcatMax(),
|
||||
BuiltinStrcmp(), BuiltinStrInList(), BuiltinStrlen(), BuiltinSubitems(),
|
||||
BuiltinSublist(),BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundArticles(),
|
||||
BuiltinSwapAroundComma(), BuiltinSwitch(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user