mercurial/templateutil.py
author Yuya Nishihara <yuya@tcha.org>
Fri, 23 Mar 2018 20:34:12 +0900
changeset 37162 9ab3491f84c2
parent 37161 0023da2910c9
child 37163 0fb28899e81a
permissions -rw-r--r--
templater: extract unwrapinteger() function from evalinteger()
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
     1
# templateutil.py - utility for template evaluation
1909
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
     2
#
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
     3
# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
     4
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8223
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9842
diff changeset
     6
# GNU General Public License version 2 or any later version.
1909
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
     7
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
     8
from __future__ import absolute_import
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
     9
17982
e06e9fd2d99f template engine: convert generator-based iterator to list-based iterator
Weiwen <weiwen@fb.com>
parents: 17890
diff changeset
    10
import types
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    11
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    12
from .i18n import _
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    13
from . import (
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    14
    error,
30615
bb77654dc7ae py3: replace os.sep with pycompat.ossep (part 3 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
    15
    pycompat,
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    16
    util,
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    17
)
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
    18
from .utils import (
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
    19
    stringutil,
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
    20
)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    21
36444
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36443
diff changeset
    22
class ResourceUnavailable(error.Abort):
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36443
diff changeset
    23
    pass
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36443
diff changeset
    24
36443
8dbd97aef915 templater: move specialized exception types to top
Yuya Nishihara <yuya@tcha.org>
parents: 36245
diff changeset
    25
class TemplateNotFound(error.Abort):
8dbd97aef915 templater: move specialized exception types to top
Yuya Nishihara <yuya@tcha.org>
parents: 36245
diff changeset
    26
    pass
8dbd97aef915 templater: move specialized exception types to top
Yuya Nishihara <yuya@tcha.org>
parents: 36245
diff changeset
    27
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    28
class hybrid(object):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    29
    """Wrapper for list or dict to support legacy template
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    30
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    31
    This class allows us to handle both:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    32
    - "{files}" (legacy command-line-specific list hack) and
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    33
    - "{files % '{file}\n'}" (hgweb-style with inlining and function support)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    34
    and to access raw values:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    35
    - "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    36
    - "{get(extras, key)}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    37
    - "{files|json}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    38
    """
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    39
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    40
    def __init__(self, gen, values, makemap, joinfmt, keytype=None):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    41
        if gen is not None:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    42
            self.gen = gen  # generator or function returning generator
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    43
        self._values = values
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    44
        self._makemap = makemap
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    45
        self.joinfmt = joinfmt
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    46
        self.keytype = keytype  # hint for 'x in y' where type(x) is unresolved
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    47
    def gen(self):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    48
        """Default generator to stringify this as {join(self, ' ')}"""
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    49
        for i, x in enumerate(self._values):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    50
            if i > 0:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    51
                yield ' '
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    52
            yield self.joinfmt(x)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    53
    def itermaps(self):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    54
        makemap = self._makemap
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    55
        for x in self._values:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    56
            yield makemap(x)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    57
    def __contains__(self, x):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    58
        return x in self._values
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    59
    def __getitem__(self, key):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    60
        return self._values[key]
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    61
    def __len__(self):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    62
        return len(self._values)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    63
    def __iter__(self):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    64
        return iter(self._values)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    65
    def __getattr__(self, name):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    66
        if name not in (r'get', r'items', r'iteritems', r'iterkeys',
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    67
                        r'itervalues', r'keys', r'values'):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    68
            raise AttributeError(name)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    69
        return getattr(self._values, name)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    70
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    71
class mappable(object):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    72
    """Wrapper for non-list/dict object to support map operation
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    73
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    74
    This class allows us to handle both:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    75
    - "{manifest}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    76
    - "{manifest % '{rev}:{node}'}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    77
    - "{manifest.rev}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    78
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    79
    Unlike a hybrid, this does not simulate the behavior of the underling
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    80
    value. Use unwrapvalue() or unwraphybrid() to obtain the inner object.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    81
    """
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    82
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    83
    def __init__(self, gen, key, value, makemap):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    84
        if gen is not None:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    85
            self.gen = gen  # generator or function returning generator
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    86
        self._key = key
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    87
        self._value = value  # may be generator of strings
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    88
        self._makemap = makemap
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    89
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    90
    def gen(self):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    91
        yield pycompat.bytestr(self._value)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    92
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    93
    def tomap(self):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    94
        return self._makemap(self._key)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    95
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    96
    def itermaps(self):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    97
        yield self.tomap()
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    98
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
    99
def hybriddict(data, key='key', value='value', fmt=None, gen=None):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   100
    """Wrap data to support both dict-like and string-like operations"""
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   101
    prefmt = pycompat.identity
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   102
    if fmt is None:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   103
        fmt = '%s=%s'
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   104
        prefmt = pycompat.bytestr
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   105
    return hybrid(gen, data, lambda k: {key: k, value: data[k]},
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   106
                  lambda k: fmt % (prefmt(k), prefmt(data[k])))
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   107
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   108
def hybridlist(data, name, fmt=None, gen=None):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   109
    """Wrap data to support both list-like and string-like operations"""
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   110
    prefmt = pycompat.identity
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   111
    if fmt is None:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   112
        fmt = '%s'
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   113
        prefmt = pycompat.bytestr
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   114
    return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   115
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   116
def unwraphybrid(thing):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   117
    """Return an object which can be stringified possibly by using a legacy
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   118
    template"""
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   119
    gen = getattr(thing, 'gen', None)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   120
    if gen is None:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   121
        return thing
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   122
    if callable(gen):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   123
        return gen()
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   124
    return gen
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   125
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   126
def unwrapvalue(thing):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   127
    """Move the inner value object out of the wrapper"""
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   128
    if not util.safehasattr(thing, '_value'):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   129
        return thing
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   130
    return thing._value
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   131
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   132
def wraphybridvalue(container, key, value):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   133
    """Wrap an element of hybrid container to be mappable
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   134
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   135
    The key is passed to the makemap function of the given container, which
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   136
    should be an item generated by iter(container).
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   137
    """
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   138
    makemap = getattr(container, '_makemap', None)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   139
    if makemap is None:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   140
        return value
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   141
    if util.safehasattr(value, '_makemap'):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   142
        # a nested hybrid list/dict, which has its own way of map operation
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   143
        return value
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   144
    return mappable(None, key, value, makemap)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   145
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   146
def compatdict(context, mapping, name, data, key='key', value='value',
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   147
               fmt=None, plural=None, separator=' '):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   148
    """Wrap data like hybriddict(), but also supports old-style list template
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   149
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   150
    This exists for backward compatibility with the old-style template. Use
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   151
    hybriddict() for new template keywords.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   152
    """
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   153
    c = [{key: k, value: v} for k, v in data.iteritems()]
37068
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   154
    f = _showcompatlist(context, mapping, name, c, plural, separator)
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   155
    return hybriddict(data, key=key, value=value, fmt=fmt, gen=f)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   156
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   157
def compatlist(context, mapping, name, data, element=None, fmt=None,
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   158
               plural=None, separator=' '):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   159
    """Wrap data like hybridlist(), but also supports old-style list template
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   160
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   161
    This exists for backward compatibility with the old-style template. Use
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   162
    hybridlist() for new template keywords.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   163
    """
37068
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   164
    f = _showcompatlist(context, mapping, name, data, plural, separator)
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   165
    return hybridlist(data, name=element or name, fmt=fmt, gen=f)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   166
37068
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   167
def _showcompatlist(context, mapping, name, values, plural=None, separator=' '):
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   168
    """Return a generator that renders old-style list template
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   169
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   170
    name is name of key in template map.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   171
    values is list of strings or dicts.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   172
    plural is plural of name, if not simply name + 's'.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   173
    separator is used to join values as a string
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   174
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   175
    expansion works like this, given name 'foo'.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   176
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   177
    if values is empty, expand 'no_foos'.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   178
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   179
    if 'foo' not in template map, return values as a string,
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   180
    joined by 'separator'.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   181
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   182
    expand 'start_foos'.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   183
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   184
    for each value, expand 'foo'. if 'last_foo' in template
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   185
    map, expand it instead of 'foo' for last key.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   186
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   187
    expand 'end_foos'.
37068
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   188
    """
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   189
    if not plural:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   190
        plural = name + 's'
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   191
    if not values:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   192
        noname = 'no_' + plural
37068
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   193
        if context.preload(noname):
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   194
            yield context.process(noname, mapping)
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   195
        return
37068
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   196
    if not context.preload(name):
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   197
        if isinstance(values[0], bytes):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   198
            yield separator.join(values)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   199
        else:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   200
            for v in values:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   201
                r = dict(v)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   202
                r.update(mapping)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   203
                yield r
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   204
        return
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   205
    startname = 'start_' + plural
37068
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   206
    if context.preload(startname):
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   207
        yield context.process(startname, mapping)
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   208
    def one(v, tag=name):
37074
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   209
        vmapping = {}
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   210
        try:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   211
            vmapping.update(v)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   212
        # Python 2 raises ValueError if the type of v is wrong. Python
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   213
        # 3 raises TypeError.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   214
        except (AttributeError, TypeError, ValueError):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   215
            try:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   216
                # Python 2 raises ValueError trying to destructure an e.g.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   217
                # bytes. Python 3 raises TypeError.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   218
                for a, b in v:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   219
                    vmapping[a] = b
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   220
            except (TypeError, ValueError):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   221
                vmapping[name] = v
37074
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   222
        vmapping = context.overlaymap(mapping, vmapping)
37068
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   223
        return context.process(tag, vmapping)
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   224
    lastname = 'last_' + name
37068
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   225
    if context.preload(lastname):
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   226
        last = values.pop()
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   227
    else:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   228
        last = None
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   229
    for v in values:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   230
        yield one(v)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   231
    if last is not None:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   232
        yield one(last, tag=lastname)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   233
    endname = 'end_' + plural
37068
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   234
    if context.preload(endname):
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   235
        yield context.process(endname, mapping)
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   236
37157
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   237
def flatten(thing):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   238
    """Yield a single stream from a possibly nested set of iterators"""
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   239
    thing = unwraphybrid(thing)
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   240
    if isinstance(thing, bytes):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   241
        yield thing
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   242
    elif isinstance(thing, str):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   243
        # We can only hit this on Python 3, and it's here to guard
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   244
        # against infinite recursion.
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   245
        raise error.ProgrammingError('Mercurial IO including templates is done'
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   246
                                     ' with bytes, not strings, got %r' % thing)
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   247
    elif thing is None:
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   248
        pass
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   249
    elif not util.safehasattr(thing, '__iter__'):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   250
        yield pycompat.bytestr(thing)
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   251
    else:
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   252
        for i in thing:
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   253
            i = unwraphybrid(i)
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   254
            if isinstance(i, bytes):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   255
                yield i
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   256
            elif i is None:
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   257
                pass
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   258
            elif not util.safehasattr(i, '__iter__'):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   259
                yield pycompat.bytestr(i)
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   260
            else:
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   261
                for j in flatten(i):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   262
                    yield j
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37104
diff changeset
   263
36920
6ff6e1d6b5b8 templater: move stringify() to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36913
diff changeset
   264
def stringify(thing):
6ff6e1d6b5b8 templater: move stringify() to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36913
diff changeset
   265
    """Turn values into bytes by converting into text and concatenating them"""
37158
e09d2183e226 templateutil: reimplement stringify() using flatten()
Yuya Nishihara <yuya@tcha.org>
parents: 37157
diff changeset
   266
    if isinstance(thing, bytes):
e09d2183e226 templateutil: reimplement stringify() using flatten()
Yuya Nishihara <yuya@tcha.org>
parents: 37157
diff changeset
   267
        return thing  # retain localstr to be round-tripped
e09d2183e226 templateutil: reimplement stringify() using flatten()
Yuya Nishihara <yuya@tcha.org>
parents: 37157
diff changeset
   268
    return b''.join(flatten(thing))
36920
6ff6e1d6b5b8 templater: move stringify() to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36913
diff changeset
   269
31927
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   270
def findsymbolicname(arg):
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   271
    """Find symbolic name for the given compiled expression; returns None
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   272
    if nothing found reliably"""
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   273
    while True:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   274
        func, data = arg
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   275
        if func is runsymbol:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   276
            return data
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   277
        elif func is runfilter:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   278
            arg = data[0]
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   279
        else:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   280
            return None
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   281
34326
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   282
def evalrawexp(context, mapping, arg):
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   283
    """Evaluate given argument as a bare template object which may require
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   284
    further processing (such as folding generator of strings)"""
26124
604a7c941103 templater: extract helper that evaluates filter or function argument
Yuya Nishihara <yuya@tcha.org>
parents: 26106
diff changeset
   285
    func, data = arg
34326
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   286
    return func(context, mapping, data)
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   287
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   288
def evalfuncarg(context, mapping, arg):
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   289
    """Evaluate given argument as value type"""
37161
0023da2910c9 templater: extract type conversion from evalfuncarg()
Yuya Nishihara <yuya@tcha.org>
parents: 37160
diff changeset
   290
    return _unwrapvalue(evalrawexp(context, mapping, arg))
0023da2910c9 templater: extract type conversion from evalfuncarg()
Yuya Nishihara <yuya@tcha.org>
parents: 37160
diff changeset
   291
0023da2910c9 templater: extract type conversion from evalfuncarg()
Yuya Nishihara <yuya@tcha.org>
parents: 37160
diff changeset
   292
# TODO: unify this with unwrapvalue() once the bug of templatefunc.join()
0023da2910c9 templater: extract type conversion from evalfuncarg()
Yuya Nishihara <yuya@tcha.org>
parents: 37160
diff changeset
   293
# is fixed. we can't do that right now because join() has to take a generator
0023da2910c9 templater: extract type conversion from evalfuncarg()
Yuya Nishihara <yuya@tcha.org>
parents: 37160
diff changeset
   294
# of byte strings as it is, not a lazy byte string.
0023da2910c9 templater: extract type conversion from evalfuncarg()
Yuya Nishihara <yuya@tcha.org>
parents: 37160
diff changeset
   295
def _unwrapvalue(thing):
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   296
    thing = unwrapvalue(thing)
34326
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   297
    # evalrawexp() may return string, generator of strings or arbitrary object
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   298
    # such as date tuple, but filter does not want generator.
26124
604a7c941103 templater: extract helper that evaluates filter or function argument
Yuya Nishihara <yuya@tcha.org>
parents: 26106
diff changeset
   299
    if isinstance(thing, types.GeneratorType):
604a7c941103 templater: extract helper that evaluates filter or function argument
Yuya Nishihara <yuya@tcha.org>
parents: 26106
diff changeset
   300
        thing = stringify(thing)
604a7c941103 templater: extract helper that evaluates filter or function argument
Yuya Nishihara <yuya@tcha.org>
parents: 26106
diff changeset
   301
    return thing
604a7c941103 templater: extract helper that evaluates filter or function argument
Yuya Nishihara <yuya@tcha.org>
parents: 26106
diff changeset
   302
29816
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29815
diff changeset
   303
def evalboolean(context, mapping, arg):
29817
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29816
diff changeset
   304
    """Evaluate given argument as boolean, but also takes boolean literals"""
29816
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29815
diff changeset
   305
    func, data = arg
29817
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29816
diff changeset
   306
    if func is runsymbol:
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29816
diff changeset
   307
        thing = func(context, mapping, data, default=None)
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29816
diff changeset
   308
        if thing is None:
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29816
diff changeset
   309
            # not a template keyword, takes as a boolean literal
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   310
            thing = stringutil.parsebool(data)
29817
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29816
diff changeset
   311
    else:
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29816
diff changeset
   312
        thing = func(context, mapping, data)
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   313
    thing = unwrapvalue(thing)
29816
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29815
diff changeset
   314
    if isinstance(thing, bool):
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29815
diff changeset
   315
        return thing
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29815
diff changeset
   316
    # other objects are evaluated as strings, which means 0 is True, but
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29815
diff changeset
   317
    # empty dict/list should be False as they are expected to be ''
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29815
diff changeset
   318
    return bool(stringify(thing))
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29815
diff changeset
   319
34581
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   320
def evalinteger(context, mapping, arg, err=None):
37162
9ab3491f84c2 templater: extract unwrapinteger() function from evalinteger()
Yuya Nishihara <yuya@tcha.org>
parents: 37161
diff changeset
   321
    return unwrapinteger(evalrawexp(context, mapping, arg), err)
9ab3491f84c2 templater: extract unwrapinteger() function from evalinteger()
Yuya Nishihara <yuya@tcha.org>
parents: 37161
diff changeset
   322
9ab3491f84c2 templater: extract unwrapinteger() function from evalinteger()
Yuya Nishihara <yuya@tcha.org>
parents: 37161
diff changeset
   323
def unwrapinteger(thing, err=None):
9ab3491f84c2 templater: extract unwrapinteger() function from evalinteger()
Yuya Nishihara <yuya@tcha.org>
parents: 37161
diff changeset
   324
    thing = _unwrapvalue(thing)
28343
a6c2310b3827 templater: factor out function that evaluates argument as integer
Yuya Nishihara <yuya@tcha.org>
parents: 28334
diff changeset
   325
    try:
37162
9ab3491f84c2 templater: extract unwrapinteger() function from evalinteger()
Yuya Nishihara <yuya@tcha.org>
parents: 37161
diff changeset
   326
        return int(thing)
28344
ac371d4c007f templater: drop redundant type conversion when evaluating integer argument
Yuya Nishihara <yuya@tcha.org>
parents: 28343
diff changeset
   327
    except (TypeError, ValueError):
34581
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   328
        raise error.ParseError(err or _('not an integer'))
28343
a6c2310b3827 templater: factor out function that evaluates argument as integer
Yuya Nishihara <yuya@tcha.org>
parents: 28334
diff changeset
   329
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   330
def evalstring(context, mapping, arg):
34326
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   331
    return stringify(evalrawexp(context, mapping, arg))
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   332
28373
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   333
def evalstringliteral(context, mapping, arg):
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   334
    """Evaluate given argument as string template, but returns symbol name
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   335
    if it is unknown"""
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   336
    func, data = arg
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   337
    if func is runsymbol:
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   338
        thing = func(context, mapping, data, default=data)
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   339
    else:
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   340
        thing = func(context, mapping, data)
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   341
    return stringify(thing)
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   342
34581
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   343
_evalfuncbytype = {
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   344
    bytes: evalstring,
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   345
    int: evalinteger,
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   346
}
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   347
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   348
def evalastype(context, mapping, arg, typ):
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   349
    """Evaluate given argument and coerce its type"""
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   350
    try:
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   351
        f = _evalfuncbytype[typ]
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   352
    except KeyError:
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   353
        raise error.ProgrammingError('invalid type specified: %r' % typ)
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   354
    return f(context, mapping, arg)
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   355
25002
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   356
def runinteger(context, mapping, data):
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   357
    return int(data)
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   358
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   359
def runstring(context, mapping, data):
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   360
    return data
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   361
27939
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   362
def _recursivesymbolblocker(key):
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   363
    def showrecursion(**args):
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   364
        raise error.Abort(_("recursive reference '%s' in template") % key)
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   365
    return showrecursion
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   366
28373
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   367
def runsymbol(context, mapping, key, default=''):
35467
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   368
    v = context.symbol(mapping, key)
19770
0361163efbaf templater: support using templates with non-standard names from map file
Alexander Plavin <alexander@plav.in>
parents: 19390
diff changeset
   369
    if v is None:
27939
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   370
        # put poison to cut recursion. we can't move this to parsing phase
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   371
        # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   372
        safemapping = mapping.copy()
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   373
        safemapping[key] = _recursivesymbolblocker(key)
19770
0361163efbaf templater: support using templates with non-standard names from map file
Alexander Plavin <alexander@plav.in>
parents: 19390
diff changeset
   374
        try:
27939
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   375
            v = context.process(key, safemapping)
19770
0361163efbaf templater: support using templates with non-standard names from map file
Alexander Plavin <alexander@plav.in>
parents: 19390
diff changeset
   376
        except TemplateNotFound:
28373
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   377
            v = default
36445
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36444
diff changeset
   378
    if callable(v) and getattr(v, '_requires', None) is None:
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36444
diff changeset
   379
        # old templatekw: expand all keywords and resources
37070
1101d6747d2d templater: drop 'templ' from resources dict
Yuya Nishihara <yuya@tcha.org>
parents: 37068
diff changeset
   380
        # (TODO: deprecate this after porting web template keywords to new API)
37073
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   381
        props = {k: context._resources.lookup(context, mapping, k)
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   382
                 for k in context._resources.knownkeys()}
37070
1101d6747d2d templater: drop 'templ' from resources dict
Yuya Nishihara <yuya@tcha.org>
parents: 37068
diff changeset
   383
        # pass context to _showcompatlist() through templatekw._showlist()
1101d6747d2d templater: drop 'templ' from resources dict
Yuya Nishihara <yuya@tcha.org>
parents: 37068
diff changeset
   384
        props['templ'] = context
35468
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35467
diff changeset
   385
        props.update(mapping)
35588
dadbf213a765 py3: convert dict keys' to str before passing as kwargs
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35481
diff changeset
   386
        return v(**pycompat.strkwargs(props))
36445
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36444
diff changeset
   387
    if callable(v):
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36444
diff changeset
   388
        # new templatekw
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36444
diff changeset
   389
        try:
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36444
diff changeset
   390
            return v(context, mapping)
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36444
diff changeset
   391
        except ResourceUnavailable:
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36444
diff changeset
   392
            # unsupported keyword is mapped to empty just like unknown keyword
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36444
diff changeset
   393
            return None
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   394
    return v
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   395
25595
a7dd6692e5cb templater: move runtemplate function out of buildmap/runmap pair
Yuya Nishihara <yuya@tcha.org>
parents: 25580
diff changeset
   396
def runtemplate(context, mapping, template):
34326
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   397
    for arg in template:
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   398
        yield evalrawexp(context, mapping, arg)
25595
a7dd6692e5cb templater: move runtemplate function out of buildmap/runmap pair
Yuya Nishihara <yuya@tcha.org>
parents: 25580
diff changeset
   399
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   400
def runfilter(context, mapping, data):
26125
c990afab2243 templater: drop unneeded destructuring of argument tuple at buildfilter
Yuya Nishihara <yuya@tcha.org>
parents: 26124
diff changeset
   401
    arg, filt = data
c990afab2243 templater: drop unneeded destructuring of argument tuple at buildfilter
Yuya Nishihara <yuya@tcha.org>
parents: 26124
diff changeset
   402
    thing = evalfuncarg(context, mapping, arg)
17383
099c778ceb33 templater: abort when a template filter raises an exception (issue2987)
Neil Kodner <neilk@fb.com>
parents: 17334
diff changeset
   403
    try:
24280
6c55e37ba5f2 templater: allow piping generator-type function output to filters
Yuya Nishihara <yuya@tcha.org>
parents: 24240
diff changeset
   404
        return filt(thing)
17383
099c778ceb33 templater: abort when a template filter raises an exception (issue2987)
Neil Kodner <neilk@fb.com>
parents: 17334
diff changeset
   405
    except (ValueError, AttributeError, TypeError):
31927
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   406
        sym = findsymbolicname(arg)
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   407
        if sym:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   408
            msg = (_("template filter '%s' is not compatible with keyword '%s'")
34838
d3ea6a1c798f templater: use pycompat.sysbytes to bytes-ify some __name__ attrs
Augie Fackler <augie@google.com>
parents: 34808
diff changeset
   409
                   % (pycompat.sysbytes(filt.__name__), sym))
17383
099c778ceb33 templater: abort when a template filter raises an exception (issue2987)
Neil Kodner <neilk@fb.com>
parents: 17334
diff changeset
   410
        else:
34838
d3ea6a1c798f templater: use pycompat.sysbytes to bytes-ify some __name__ attrs
Augie Fackler <augie@google.com>
parents: 34808
diff changeset
   411
            msg = (_("incompatible use of template filter '%s'")
d3ea6a1c798f templater: use pycompat.sysbytes to bytes-ify some __name__ attrs
Augie Fackler <augie@google.com>
parents: 34808
diff changeset
   412
                   % pycompat.sysbytes(filt.__name__))
31927
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   413
        raise error.Abort(msg)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   414
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   415
def runmap(context, mapping, data):
34326
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   416
    darg, targ = data
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   417
    d = evalrawexp(context, mapping, darg)
27891
ac8c0ee5c3b8 templater: make _hybrid not callable to avoid conflicting semantics
Yuya Nishihara <yuya@tcha.org>
parents: 27637
diff changeset
   418
    if util.safehasattr(d, 'itermaps'):
28349
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   419
        diter = d.itermaps()
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   420
    else:
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   421
        try:
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   422
            diter = iter(d)
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   423
        except TypeError:
34326
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   424
            sym = findsymbolicname(darg)
34324
e473f482b9b3 templater: use helper function to get name of non-iterable keyword
Yuya Nishihara <yuya@tcha.org>
parents: 34287
diff changeset
   425
            if sym:
e473f482b9b3 templater: use helper function to get name of non-iterable keyword
Yuya Nishihara <yuya@tcha.org>
parents: 34287
diff changeset
   426
                raise error.ParseError(_("keyword '%s' is not iterable") % sym)
28349
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   427
            else:
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   428
                raise error.ParseError(_("%r is not iterable") % d)
17631
0b241d7a8c62 templating: make new-style templating features work with command line lists
Matt Mackall <mpm@selenic.com>
parents: 17383
diff changeset
   429
31807
e6eb86b154c5 templater: provide loop counter as "index" keyword
Yuya Nishihara <yuya@tcha.org>
parents: 31806
diff changeset
   430
    for i, v in enumerate(diter):
31806
8f203b491bb5 templater: rename variable "i" to "v" in runmap()
Yuya Nishihara <yuya@tcha.org>
parents: 31521
diff changeset
   431
        if isinstance(v, dict):
37074
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   432
            lm = context.overlaymap(mapping, v)
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   433
            lm['index'] = i
34326
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34325
diff changeset
   434
            yield evalrawexp(context, lm, targ)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   435
        else:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   436
            # v is not an iterable of dicts, this happen when 'key'
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   437
            # has been fully expanded already and format is useless.
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   438
            # If so, return the expanded value.
31806
8f203b491bb5 templater: rename variable "i" to "v" in runmap()
Yuya Nishihara <yuya@tcha.org>
parents: 31521
diff changeset
   439
            yield v
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   440
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   441
def runmember(context, mapping, data):
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   442
    darg, memb = data
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   443
    d = evalrawexp(context, mapping, darg)
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   444
    if util.safehasattr(d, 'tomap'):
37074
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   445
        lm = context.overlaymap(mapping, d.tomap())
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   446
        return runsymbol(context, lm, memb)
34536
4c1cfe54c08d templater: extend dot operator as a short for get(dict, key)
Yuya Nishihara <yuya@tcha.org>
parents: 34535
diff changeset
   447
    if util.safehasattr(d, 'get'):
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   448
        return getdictitem(d, memb)
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   449
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   450
    sym = findsymbolicname(darg)
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   451
    if sym:
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   452
        raise error.ParseError(_("keyword '%s' has no member") % sym)
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   453
    else:
36545
ab7f86a748e6 py3: drop b'' from error message generated by templater.runmember()
Yuya Nishihara <yuya@tcha.org>
parents: 36544
diff changeset
   454
        raise error.ParseError(_("%r has no member") % pycompat.bytestr(d))
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   455
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   456
def runnegate(context, mapping, data):
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   457
    data = evalinteger(context, mapping, data,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   458
                       _('negation needs an integer argument'))
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   459
    return -data
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   460
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   461
def runarithmetic(context, mapping, data):
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   462
    func, left, right = data
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   463
    left = evalinteger(context, mapping, left,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   464
                       _('arithmetic only defined on integers'))
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   465
    right = evalinteger(context, mapping, right,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   466
                        _('arithmetic only defined on integers'))
30116
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   467
    try:
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   468
        return func(left, right)
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   469
    except ZeroDivisionError:
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   470
        raise error.Abort(_('division by zero is not defined'))
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   471
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   472
def getdictitem(dictarg, key):
34534
b3073e175c17 templater: wrap get/min/max result so map operation can apply to element
Yuya Nishihara <yuya@tcha.org>
parents: 34458
diff changeset
   473
    val = dictarg.get(key)
b3073e175c17 templater: wrap get/min/max result so map operation can apply to element
Yuya Nishihara <yuya@tcha.org>
parents: 34458
diff changeset
   474
    if val is None:
b3073e175c17 templater: wrap get/min/max result so map operation can apply to element
Yuya Nishihara <yuya@tcha.org>
parents: 34458
diff changeset
   475
        return
36921
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36920
diff changeset
   476
    return wraphybridvalue(dictarg, key, val)