mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 02:34:06 -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`.
|
* ``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`.
|
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.
|
* ``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
|
* ``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).
|
"{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
|
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,
|
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,
|
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.
|
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`,
|
* ``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.
|
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,
|
* ``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.
|
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
|
* ``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.
|
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
|
* ``list_union(list1, list2, separator)`` -- return a list made by merging the items in ``list1`` and ``list2``, removing
|
||||||
a case-insensitive comparison. If items differ in case, the one in ``list1`` is used. The items in ``list1`` and ``list2`` are separated by
|
duplicate items using a case-insensitive comparison. If items differ in case, the one in ``list1`` is used. The items
|
||||||
``separator``, as are the items in the returned list.
|
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
|
* ``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.
|
``y`` is not a number.
|
||||||
* ``multiply(x, y, ...)`` -- returns the product of its arguments. Throws an exception if any argument 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**
|
**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
|
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
|
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 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.
|
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
|
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,
|
def __init__(self, parent, text, mi=None, fm=None, color_field=None,
|
||||||
icon_field_key=None, icon_rule_kind=None, doing_emblem=False,
|
icon_field_key=None, icon_rule_kind=None, doing_emblem=False,
|
||||||
text_is_placeholder=False, dialog_is_st_editor=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)
|
QDialog.__init__(self, parent)
|
||||||
Ui_TemplateDialog.__init__(self)
|
Ui_TemplateDialog.__init__(self)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
@ -224,7 +224,10 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
|||||||
self.iconing = icon_field_key is not None
|
self.iconing = icon_field_key is not None
|
||||||
self.embleming = doing_emblem
|
self.embleming = doing_emblem
|
||||||
self.dialog_is_st_editor = dialog_is_st_editor
|
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 = []
|
cols = []
|
||||||
if fm is not None:
|
if fm is not None:
|
||||||
@ -316,7 +319,8 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
|
|||||||
self.setWindowIcon(icon)
|
self.setWindowIcon(icon)
|
||||||
|
|
||||||
self.all_functions = all_functions if all_functions else formatter_functions().get_functions()
|
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.last_text = ''
|
||||||
self.highlighter = TemplateHighlighter(self.textbox.document(), builtin_functions=self.builtins)
|
self.highlighter = TemplateHighlighter(self.textbox.document(), builtin_functions=self.builtins)
|
||||||
|
@ -33,7 +33,8 @@ class Node(object):
|
|||||||
NODE_FIRST_NON_EMPTY = 12
|
NODE_FIRST_NON_EMPTY = 12
|
||||||
NODE_FOR = 13
|
NODE_FOR = 13
|
||||||
NODE_GLOBALS = 14
|
NODE_GLOBALS = 14
|
||||||
NODE_CONTAINS = 15
|
NODE_SET_GLOBALS = 15
|
||||||
|
NODE_CONTAINS = 16
|
||||||
|
|
||||||
|
|
||||||
class IfNode(Node):
|
class IfNode(Node):
|
||||||
@ -92,6 +93,13 @@ class GlobalsNode(Node):
|
|||||||
self.expression_list = expression_list
|
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):
|
class StringInfixNode(Node):
|
||||||
def __init__(self, operator, left, right):
|
def __init__(self, operator, left, right):
|
||||||
Node.__init__(self)
|
Node.__init__(self)
|
||||||
@ -447,7 +455,7 @@ class _Parser(object):
|
|||||||
return FirstNonEmptyNode(arguments)
|
return FirstNonEmptyNode(arguments)
|
||||||
if (id_ == 'assign' and len(arguments) == 2 and arguments[0].node_type == Node.NODE_RVALUE):
|
if (id_ == 'assign' and len(arguments) == 2 and arguments[0].node_type == Node.NODE_RVALUE):
|
||||||
return AssignNode(arguments[0].name, arguments[1])
|
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 = []
|
new_args = []
|
||||||
for arg in arguments:
|
for arg in arguments:
|
||||||
if arg.node_type not in (Node.NODE_ASSIGN, Node.NODE_RVALUE):
|
if arg.node_type not in (Node.NODE_ASSIGN, Node.NODE_RVALUE):
|
||||||
@ -458,6 +466,8 @@ class _Parser(object):
|
|||||||
new_args.append(arg)
|
new_args.append(arg)
|
||||||
if id_ == 'arguments':
|
if id_ == 'arguments':
|
||||||
return ArgumentsNode(new_args)
|
return ArgumentsNode(new_args)
|
||||||
|
if id_ == 'set_globals':
|
||||||
|
return SetGlobalsNode(new_args)
|
||||||
return GlobalsNode(new_args)
|
return GlobalsNode(new_args)
|
||||||
if id_ == 'contains' and len(arguments) == 4:
|
if id_ == 'contains' and len(arguments) == 4:
|
||||||
return ContainsNode(arguments)
|
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))
|
res = self.locals[arg.left] = self.global_vars.get(arg.left, self.expr(arg.right))
|
||||||
return res
|
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):
|
def do_node_constant(self, prog):
|
||||||
return prog.value
|
return prog.value
|
||||||
|
|
||||||
@ -668,6 +684,7 @@ class _Interpreter(object):
|
|||||||
Node.NODE_FIRST_NON_EMPTY:do_node_first_non_empty,
|
Node.NODE_FIRST_NON_EMPTY:do_node_first_non_empty,
|
||||||
Node.NODE_FOR: do_node_for,
|
Node.NODE_FOR: do_node_for,
|
||||||
Node.NODE_GLOBALS: do_node_globals,
|
Node.NODE_GLOBALS: do_node_globals,
|
||||||
|
Node.NODE_SET_GLOBALS: do_node_set_globals,
|
||||||
Node.NODE_CONTAINS: do_node_contains,
|
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 '
|
'not_found_val. The pattern and found_value can be repeated as '
|
||||||
'many times as desired, permitting returning different values '
|
'many times as desired, permitting returning different values '
|
||||||
'depending on the search. The patterns are checked in order. The '
|
'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']
|
aliases = ['list_contains']
|
||||||
|
|
||||||
def evaluate(self, formatter, kwargs, mi, locals, val, sep, *args):
|
def evaluate(self, formatter, kwargs, mi, locals, val, sep, *args):
|
||||||
@ -814,10 +814,13 @@ class BuiltinCount(BuiltinFormatterFunction):
|
|||||||
name = 'count'
|
name = 'count'
|
||||||
arg_count = 2
|
arg_count = 2
|
||||||
category = 'List manipulation'
|
category = 'List manipulation'
|
||||||
|
aliases = ['list_count']
|
||||||
|
|
||||||
__doc__ = doc = _('count(val, separator) -- interprets the value as a list of items '
|
__doc__ = doc = _('count(val, separator) -- interprets the value as a list of items '
|
||||||
'separated by `separator`, returning the number of items in the '
|
'separated by `separator`, returning the number of items in the '
|
||||||
'list. Most lists use a comma as the separator, but authors '
|
'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):
|
def evaluate(self, formatter, kwargs, mi, locals, val, sep):
|
||||||
return unicode_type(len([v for v in val.split(sep) if v]))
|
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 '
|
'removing duplicate items using a case-insensitive comparison. If '
|
||||||
'items differ in case, the one in list1 is used. '
|
'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 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']
|
aliases = ['merge_lists']
|
||||||
|
|
||||||
def evaluate(self, formatter, kwargs, mi, locals, list1, list2, separator):
|
def evaluate(self, formatter, kwargs, mi, locals, list1, list2, separator):
|
||||||
@ -1917,6 +1920,24 @@ class BuiltinGlobals(BuiltinFormatterFunction):
|
|||||||
raise NotImplementedError()
|
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):
|
class BuiltinFieldExists(BuiltinFormatterFunction):
|
||||||
name = 'field_exists'
|
name = 'field_exists'
|
||||||
arg_count = 1
|
arg_count = 1
|
||||||
@ -1953,7 +1974,7 @@ _formatter_builtins = [
|
|||||||
BuiltinLowercase(), BuiltinMod(), BuiltinMultiply(), BuiltinNot(), BuiltinOndevice(),
|
BuiltinLowercase(), BuiltinMod(), BuiltinMultiply(), BuiltinNot(), BuiltinOndevice(),
|
||||||
BuiltinOr(), BuiltinPrint(), BuiltinRatingToStars(), BuiltinRawField(), BuiltinRawList(),
|
BuiltinOr(), BuiltinPrint(), BuiltinRatingToStars(), BuiltinRawField(), BuiltinRawList(),
|
||||||
BuiltinRe(), BuiltinReGroup(), BuiltinRound(), BuiltinSelect(), BuiltinSeriesSort(),
|
BuiltinRe(), BuiltinReGroup(), BuiltinRound(), BuiltinSelect(), BuiltinSeriesSort(),
|
||||||
BuiltinShorten(), BuiltinStrcat(), BuiltinStrcatMax(),
|
BuiltinSetGlobals(), BuiltinShorten(), BuiltinStrcat(), BuiltinStrcatMax(),
|
||||||
BuiltinStrcmp(), BuiltinStrInList(), BuiltinStrlen(), BuiltinSubitems(),
|
BuiltinStrcmp(), BuiltinStrInList(), BuiltinStrlen(), BuiltinSubitems(),
|
||||||
BuiltinSublist(),BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundArticles(),
|
BuiltinSublist(),BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundArticles(),
|
||||||
BuiltinSwapAroundComma(), BuiltinSwitch(),
|
BuiltinSwapAroundComma(), BuiltinSwitch(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user