mercurial/templateutil.py
author Yuya Nishihara <yuya@tcha.org>
Wed, 21 Mar 2018 12:06:18 +0900
changeset 38278 80f423a14c90
parent 38277 41ae9b3cbfb9
child 38279 fb874fc1d9b4
permissions -rw-r--r--
templater: inline wraphybridvalue() All wraphybridvalue() calls are now handled in the hybrid class.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
36919
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36918
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
36919
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36918
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
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    10
import abc
17982
e06e9fd2d99f template engine: convert generator-based iterator to list-based iterator
Weiwen <weiwen@fb.com>
parents: 17890
diff changeset
    11
import types
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    12
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    13
from .i18n import _
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    14
from . import (
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    15
    error,
30620
bb77654dc7ae py3: replace os.sep with pycompat.ossep (part 3 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30342
diff changeset
    16
    pycompat,
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    17
    util,
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    18
)
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37077
diff changeset
    19
from .utils import (
37226
67efce231633 templater: factor out function that parses argument as date tuple
Yuya Nishihara <yuya@tcha.org>
parents: 37224
diff changeset
    20
    dateutil,
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37077
diff changeset
    21
    stringutil,
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37077
diff changeset
    22
)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    23
36474
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36473
diff changeset
    24
class ResourceUnavailable(error.Abort):
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36473
diff changeset
    25
    pass
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36473
diff changeset
    26
36473
8dbd97aef915 templater: move specialized exception types to top
Yuya Nishihara <yuya@tcha.org>
parents: 36278
diff changeset
    27
class TemplateNotFound(error.Abort):
8dbd97aef915 templater: move specialized exception types to top
Yuya Nishihara <yuya@tcha.org>
parents: 36278
diff changeset
    28
    pass
8dbd97aef915 templater: move specialized exception types to top
Yuya Nishihara <yuya@tcha.org>
parents: 36278
diff changeset
    29
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    30
class wrapped(object):
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    31
    """Object requiring extra conversion prior to displaying or processing
37281
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    32
    as value
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    33
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    34
    Use unwrapvalue(), unwrapastype(), or unwraphybrid() to obtain the inner
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    35
    object.
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    36
    """
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    37
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    38
    __metaclass__ = abc.ABCMeta
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    39
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    40
    @abc.abstractmethod
38255
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    41
    def getmember(self, context, mapping, key):
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    42
        """Return a member item for the specified key
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    43
38256
688fbb758ba9 templater: resolve type of dict key in getmember()
Yuya Nishihara <yuya@tcha.org>
parents: 38255
diff changeset
    44
        The key argument may be a wrapped object.
38255
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    45
        A returned object may be either a wrapped object or a pure value
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    46
        depending on the self type.
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    47
        """
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    48
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    49
    @abc.abstractmethod
38277
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    50
    def getmin(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    51
        """Return the smallest item, which may be either a wrapped or a pure
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    52
        value depending on the self type"""
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    53
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    54
    @abc.abstractmethod
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    55
    def getmax(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    56
        """Return the largest item, which may be either a wrapped or a pure
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    57
        value depending on the self type"""
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    58
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    59
    @abc.abstractmethod
37324
c2f74b8f6b7f templater: pass context to itermaps() for future extension
Yuya Nishihara <yuya@tcha.org>
parents: 37323
diff changeset
    60
    def itermaps(self, context):
37323
8c31b434697f templater: define interface for objects which act as iterator of mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37281
diff changeset
    61
        """Yield each template mapping"""
8c31b434697f templater: define interface for objects which act as iterator of mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37281
diff changeset
    62
8c31b434697f templater: define interface for objects which act as iterator of mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37281
diff changeset
    63
    @abc.abstractmethod
37327
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
    64
    def join(self, context, mapping, sep):
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
    65
        """Join items with the separator; Returns a bytes or (possibly nested)
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
    66
        generator of bytes
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
    67
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
    68
        A pre-configured template may be rendered per item if this container
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
    69
        holds unprintable items.
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
    70
        """
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
    71
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
    72
    @abc.abstractmethod
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    73
    def show(self, context, mapping):
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    74
        """Return a bytes or (possibly nested) generator of bytes representing
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    75
        the underlying object
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    76
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    77
        A pre-configured template may be rendered if the underlying object is
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    78
        not printable.
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    79
        """
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
    80
37281
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    81
    @abc.abstractmethod
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    82
    def tovalue(self, context, mapping):
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    83
        """Move the inner value object out or create a value representation
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    84
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    85
        A returned value must be serializable by templaterfilters.json().
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    86
        """
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
    87
38238
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
    88
class wrappedbytes(wrapped):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
    89
    """Wrapper for byte string"""
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
    90
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
    91
    def __init__(self, value):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
    92
        self._value = value
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
    93
38255
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    94
    def getmember(self, context, mapping, key):
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    95
        raise error.ParseError(_('%r is not a dictionary')
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    96
                               % pycompat.bytestr(self._value))
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
    97
38277
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    98
    def getmin(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
    99
        return self._getby(context, mapping, min)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   100
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   101
    def getmax(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   102
        return self._getby(context, mapping, max)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   103
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   104
    def _getby(self, context, mapping, func):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   105
        if not self._value:
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   106
            raise error.ParseError(_('empty string'))
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   107
        return func(pycompat.iterbytestr(self._value))
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   108
38238
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   109
    def itermaps(self, context):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   110
        raise error.ParseError(_('%r is not iterable of mappings')
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   111
                               % pycompat.bytestr(self._value))
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   112
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   113
    def join(self, context, mapping, sep):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   114
        return joinitems(pycompat.iterbytestr(self._value), sep)
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   115
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   116
    def show(self, context, mapping):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   117
        return self._value
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   118
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   119
    def tovalue(self, context, mapping):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   120
        return self._value
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   121
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   122
class wrappedvalue(wrapped):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   123
    """Generic wrapper for pure non-list/dict/bytes value"""
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   124
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   125
    def __init__(self, value):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   126
        self._value = value
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   127
38255
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   128
    def getmember(self, context, mapping, key):
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   129
        raise error.ParseError(_('%r is not a dictionary') % self._value)
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   130
38277
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   131
    def getmin(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   132
        raise error.ParseError(_("%r is not iterable") % self._value)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   133
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   134
    def getmax(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   135
        raise error.ParseError(_("%r is not iterable") % self._value)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   136
38238
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   137
    def itermaps(self, context):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   138
        raise error.ParseError(_('%r is not iterable of mappings')
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   139
                               % self._value)
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   140
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   141
    def join(self, context, mapping, sep):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   142
        raise error.ParseError(_('%r is not iterable') % self._value)
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   143
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   144
    def show(self, context, mapping):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   145
        return pycompat.bytestr(self._value)
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   146
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   147
    def tovalue(self, context, mapping):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   148
        return self._value
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   149
37229
9bcf096a2da2 templatefilters: declare input type as date where appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 37228
diff changeset
   150
# stub for representing a date type; may be a real date type that can
9bcf096a2da2 templatefilters: declare input type as date where appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 37228
diff changeset
   151
# provide a readable string value
9bcf096a2da2 templatefilters: declare input type as date where appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 37228
diff changeset
   152
class date(object):
9bcf096a2da2 templatefilters: declare input type as date where appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 37228
diff changeset
   153
    pass
9bcf096a2da2 templatefilters: declare input type as date where appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 37228
diff changeset
   154
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   155
class hybrid(wrapped):
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   156
    """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: 36926
diff changeset
   157
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   158
    This class allows us to handle both:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   159
    - "{files}" (legacy command-line-specific list hack) and
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   160
    - "{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: 36926
diff changeset
   161
    and to access raw values:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   162
    - "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   163
    - "{get(extras, key)}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   164
    - "{files|json}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   165
    """
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   166
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   167
    def __init__(self, gen, values, makemap, joinfmt, keytype=None):
37325
41a5d815d2c1 templater: factor out generator of join()-ed items
Yuya Nishihara <yuya@tcha.org>
parents: 37324
diff changeset
   168
        self._gen = gen  # generator or function returning generator
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   169
        self._values = values
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   170
        self._makemap = makemap
37329
676664592313 templater: mark .joinfmt as a private attribute
Yuya Nishihara <yuya@tcha.org>
parents: 37327
diff changeset
   171
        self._joinfmt = joinfmt
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   172
        self.keytype = keytype  # hint for 'x in y' where type(x) is unresolved
37277
8c84dc8264dc templater: mark .gen as a private attribute
Yuya Nishihara <yuya@tcha.org>
parents: 37275
diff changeset
   173
38254
12b6ee9e88f3 templater: move getdictitem() to hybrid class
Yuya Nishihara <yuya@tcha.org>
parents: 38253
diff changeset
   174
    def getmember(self, context, mapping, key):
12b6ee9e88f3 templater: move getdictitem() to hybrid class
Yuya Nishihara <yuya@tcha.org>
parents: 38253
diff changeset
   175
        # TODO: maybe split hybrid list/dict types?
12b6ee9e88f3 templater: move getdictitem() to hybrid class
Yuya Nishihara <yuya@tcha.org>
parents: 38253
diff changeset
   176
        if not util.safehasattr(self._values, 'get'):
12b6ee9e88f3 templater: move getdictitem() to hybrid class
Yuya Nishihara <yuya@tcha.org>
parents: 38253
diff changeset
   177
            raise error.ParseError(_('not a dictionary'))
38256
688fbb758ba9 templater: resolve type of dict key in getmember()
Yuya Nishihara <yuya@tcha.org>
parents: 38255
diff changeset
   178
        key = unwrapastype(context, mapping, key, self.keytype)
38254
12b6ee9e88f3 templater: move getdictitem() to hybrid class
Yuya Nishihara <yuya@tcha.org>
parents: 38253
diff changeset
   179
        return self._wrapvalue(key, self._values.get(key))
12b6ee9e88f3 templater: move getdictitem() to hybrid class
Yuya Nishihara <yuya@tcha.org>
parents: 38253
diff changeset
   180
38277
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   181
    def getmin(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   182
        return self._getby(context, mapping, min)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   183
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   184
    def getmax(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   185
        return self._getby(context, mapping, max)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   186
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   187
    def _getby(self, context, mapping, func):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   188
        if not self._values:
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   189
            raise error.ParseError(_('empty sequence'))
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   190
        val = func(self._values)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   191
        return self._wrapvalue(val, val)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   192
38254
12b6ee9e88f3 templater: move getdictitem() to hybrid class
Yuya Nishihara <yuya@tcha.org>
parents: 38253
diff changeset
   193
    def _wrapvalue(self, key, val):
12b6ee9e88f3 templater: move getdictitem() to hybrid class
Yuya Nishihara <yuya@tcha.org>
parents: 38253
diff changeset
   194
        if val is None:
12b6ee9e88f3 templater: move getdictitem() to hybrid class
Yuya Nishihara <yuya@tcha.org>
parents: 38253
diff changeset
   195
            return
38278
80f423a14c90 templater: inline wraphybridvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 38277
diff changeset
   196
        if util.safehasattr(val, '_makemap'):
80f423a14c90 templater: inline wraphybridvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 38277
diff changeset
   197
            # a nested hybrid list/dict, which has its own way of map operation
80f423a14c90 templater: inline wraphybridvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 38277
diff changeset
   198
            return val
80f423a14c90 templater: inline wraphybridvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 38277
diff changeset
   199
        return mappable(None, key, val, self._makemap)
38254
12b6ee9e88f3 templater: move getdictitem() to hybrid class
Yuya Nishihara <yuya@tcha.org>
parents: 38253
diff changeset
   200
37324
c2f74b8f6b7f templater: pass context to itermaps() for future extension
Yuya Nishihara <yuya@tcha.org>
parents: 37323
diff changeset
   201
    def itermaps(self, context):
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   202
        makemap = self._makemap
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   203
        for x in self._values:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   204
            yield makemap(x)
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   205
37327
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
   206
    def join(self, context, mapping, sep):
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
   207
        # TODO: switch gen to (context, mapping) API?
37329
676664592313 templater: mark .joinfmt as a private attribute
Yuya Nishihara <yuya@tcha.org>
parents: 37327
diff changeset
   208
        return joinitems((self._joinfmt(x) for x in self._values), sep)
37327
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
   209
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   210
    def show(self, context, mapping):
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   211
        # TODO: switch gen to (context, mapping) API?
37277
8c84dc8264dc templater: mark .gen as a private attribute
Yuya Nishihara <yuya@tcha.org>
parents: 37275
diff changeset
   212
        gen = self._gen
37325
41a5d815d2c1 templater: factor out generator of join()-ed items
Yuya Nishihara <yuya@tcha.org>
parents: 37324
diff changeset
   213
        if gen is None:
37327
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
   214
            return self.join(context, mapping, ' ')
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   215
        if callable(gen):
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   216
            return gen()
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   217
        return gen
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   218
37281
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
   219
    def tovalue(self, context, mapping):
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
   220
        # TODO: return self._values and get rid of proxy methods
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
   221
        return self
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
   222
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   223
    def __contains__(self, x):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   224
        return x in self._values
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   225
    def __getitem__(self, key):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   226
        return self._values[key]
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   227
    def __len__(self):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   228
        return len(self._values)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   229
    def __iter__(self):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   230
        return iter(self._values)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   231
    def __getattr__(self, name):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   232
        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: 36926
diff changeset
   233
                        r'itervalues', r'keys', r'values'):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   234
            raise AttributeError(name)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   235
        return getattr(self._values, name)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   236
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   237
class mappable(wrapped):
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   238
    """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: 36926
diff changeset
   239
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   240
    This class allows us to handle both:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   241
    - "{manifest}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   242
    - "{manifest % '{rev}:{node}'}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   243
    - "{manifest.rev}"
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   244
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   245
    Unlike a hybrid, this does not simulate the behavior of the underling
37281
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
   246
    value.
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   247
    """
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   248
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   249
    def __init__(self, gen, key, value, makemap):
37278
b4630e332a99 templater: drop unneeded generator from mappable object
Yuya Nishihara <yuya@tcha.org>
parents: 37277
diff changeset
   250
        self._gen = gen  # generator or function returning generator
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   251
        self._key = key
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   252
        self._value = value  # may be generator of strings
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   253
        self._makemap = makemap
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   254
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   255
    def tomap(self):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   256
        return self._makemap(self._key)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   257
38255
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   258
    def getmember(self, context, mapping, key):
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   259
        w = makewrapped(context, mapping, self._value)
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   260
        return w.getmember(context, mapping, key)
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   261
38277
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   262
    def getmin(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   263
        w = makewrapped(context, mapping, self._value)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   264
        return w.getmin(context, mapping)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   265
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   266
    def getmax(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   267
        w = makewrapped(context, mapping, self._value)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   268
        return w.getmax(context, mapping)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   269
37324
c2f74b8f6b7f templater: pass context to itermaps() for future extension
Yuya Nishihara <yuya@tcha.org>
parents: 37323
diff changeset
   270
    def itermaps(self, context):
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   271
        yield self.tomap()
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   272
37327
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
   273
    def join(self, context, mapping, sep):
38240
8bded7eae26c templater: consistently join() string-like object per character (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 38238
diff changeset
   274
        w = makewrapped(context, mapping, self._value)
8bded7eae26c templater: consistently join() string-like object per character (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 38238
diff changeset
   275
        return w.join(context, mapping, sep)
37327
ebf139cbd4a1 templater: abstract away from joinfmt
Yuya Nishihara <yuya@tcha.org>
parents: 37326
diff changeset
   276
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   277
    def show(self, context, mapping):
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   278
        # TODO: switch gen to (context, mapping) API?
37277
8c84dc8264dc templater: mark .gen as a private attribute
Yuya Nishihara <yuya@tcha.org>
parents: 37275
diff changeset
   279
        gen = self._gen
37278
b4630e332a99 templater: drop unneeded generator from mappable object
Yuya Nishihara <yuya@tcha.org>
parents: 37277
diff changeset
   280
        if gen is None:
b4630e332a99 templater: drop unneeded generator from mappable object
Yuya Nishihara <yuya@tcha.org>
parents: 37277
diff changeset
   281
            return pycompat.bytestr(self._value)
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   282
        if callable(gen):
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   283
            return gen()
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   284
        return gen
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   285
37281
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
   286
    def tovalue(self, context, mapping):
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
   287
        return _unthunk(context, mapping, self._value)
26f6fc179e62 templater: define interface for objects requiring unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37280
diff changeset
   288
37399
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   289
class _mappingsequence(wrapped):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   290
    """Wrapper for sequence of template mappings
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   291
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   292
    This represents an inner template structure (i.e. a list of dicts),
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   293
    which can also be rendered by the specified named/literal template.
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   294
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   295
    Template mappings may be nested.
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   296
    """
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   297
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   298
    def __init__(self, name=None, tmpl=None, sep=''):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   299
        if name is not None and tmpl is not None:
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   300
            raise error.ProgrammingError('name and tmpl are mutually exclusive')
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   301
        self._name = name
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   302
        self._tmpl = tmpl
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   303
        self._defaultsep = sep
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   304
38255
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   305
    def getmember(self, context, mapping, key):
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   306
        raise error.ParseError(_('not a dictionary'))
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   307
38277
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   308
    def getmin(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   309
        raise error.ParseError(_('not comparable'))
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   310
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   311
    def getmax(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   312
        raise error.ParseError(_('not comparable'))
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   313
37399
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   314
    def join(self, context, mapping, sep):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   315
        mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   316
        if self._name:
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   317
            itemiter = (context.process(self._name, m) for m in mapsiter)
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   318
        elif self._tmpl:
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   319
            itemiter = (context.expand(self._tmpl, m) for m in mapsiter)
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   320
        else:
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   321
            raise error.ParseError(_('not displayable without template'))
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   322
        return joinitems(itemiter, sep)
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   323
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   324
    def show(self, context, mapping):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   325
        return self.join(context, mapping, self._defaultsep)
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   326
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   327
    def tovalue(self, context, mapping):
37502
40c7347f6848 formatter: remove template resources from nested items before generating JSON
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   328
        knownres = context.knownresourcekeys()
40c7347f6848 formatter: remove template resources from nested items before generating JSON
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   329
        items = []
40c7347f6848 formatter: remove template resources from nested items before generating JSON
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   330
        for nm in self.itermaps(context):
40c7347f6848 formatter: remove template resources from nested items before generating JSON
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   331
            # drop internal resources (recursively) which shouldn't be displayed
40c7347f6848 formatter: remove template resources from nested items before generating JSON
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   332
            lm = context.overlaymap(mapping, nm)
40c7347f6848 formatter: remove template resources from nested items before generating JSON
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   333
            items.append({k: unwrapvalue(context, lm, v)
40c7347f6848 formatter: remove template resources from nested items before generating JSON
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   334
                          for k, v in nm.iteritems() if k not in knownres})
40c7347f6848 formatter: remove template resources from nested items before generating JSON
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   335
        return items
37399
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   336
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   337
class mappinggenerator(_mappingsequence):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   338
    """Wrapper for generator of template mappings
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   339
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   340
    The function ``make(context, *args)`` should return a generator of
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   341
    mapping dicts.
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   342
    """
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   343
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   344
    def __init__(self, make, args=(), name=None, tmpl=None, sep=''):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   345
        super(mappinggenerator, self).__init__(name, tmpl, sep)
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   346
        self._make = make
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   347
        self._args = args
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   348
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   349
    def itermaps(self, context):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   350
        return self._make(context, *self._args)
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   351
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   352
class mappinglist(_mappingsequence):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   353
    """Wrapper for list of template mappings"""
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   354
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   355
    def __init__(self, mappings, name=None, tmpl=None, sep=''):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   356
        super(mappinglist, self).__init__(name, tmpl, sep)
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   357
        self._mappings = mappings
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   358
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   359
    def itermaps(self, context):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   360
        return iter(self._mappings)
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   361
37499
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   362
class mappedgenerator(wrapped):
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   363
    """Wrapper for generator of strings which acts as a list
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   364
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   365
    The function ``make(context, *args)`` should return a generator of
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   366
    byte strings, or a generator of (possibly nested) generators of byte
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   367
    strings (i.e. a generator for a list of byte strings.)
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   368
    """
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   369
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   370
    def __init__(self, make, args=()):
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   371
        self._make = make
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   372
        self._args = args
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   373
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   374
    def _gen(self, context):
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   375
        return self._make(context, *self._args)
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   376
38255
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   377
    def getmember(self, context, mapping, key):
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   378
        raise error.ParseError(_('not a dictionary'))
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   379
38277
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   380
    def getmin(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   381
        return self._getby(context, mapping, min)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   382
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   383
    def getmax(self, context, mapping):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   384
        return self._getby(context, mapping, max)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   385
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   386
    def _getby(self, context, mapping, func):
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   387
        xs = self.tovalue(context, mapping)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   388
        if not xs:
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   389
            raise error.ParseError(_('empty sequence'))
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   390
        return func(xs)
41ae9b3cbfb9 templater: abstract min/max away
Yuya Nishihara <yuya@tcha.org>
parents: 38256
diff changeset
   391
37499
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   392
    def itermaps(self, context):
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   393
        raise error.ParseError(_('list of strings is not mappable'))
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   394
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   395
    def join(self, context, mapping, sep):
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   396
        return joinitems(self._gen(context), sep)
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   397
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   398
    def show(self, context, mapping):
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   399
        return self.join(context, mapping, '')
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   400
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   401
    def tovalue(self, context, mapping):
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   402
        return [stringify(context, mapping, x) for x in self._gen(context)]
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   403
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   404
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: 36926
diff changeset
   405
    """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: 36926
diff changeset
   406
    prefmt = pycompat.identity
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   407
    if fmt is None:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   408
        fmt = '%s=%s'
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   409
        prefmt = pycompat.bytestr
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   410
    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: 36926
diff changeset
   411
                  lambda k: fmt % (prefmt(k), prefmt(data[k])))
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   412
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   413
def hybridlist(data, name, fmt=None, gen=None):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   414
    """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: 36926
diff changeset
   415
    prefmt = pycompat.identity
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   416
    if fmt is None:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   417
        fmt = '%s'
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   418
        prefmt = pycompat.bytestr
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   419
    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: 36926
diff changeset
   420
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   421
def unwraphybrid(context, mapping, thing):
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   422
    """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: 36926
diff changeset
   423
    template"""
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   424
    if not isinstance(thing, wrapped):
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   425
        return thing
37275
83e1bbd48991 templater: define interface for objects requiring unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37274
diff changeset
   426
    return thing.show(context, mapping)
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   427
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   428
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: 36926
diff changeset
   429
               fmt=None, plural=None, separator=' '):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   430
    """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: 36926
diff changeset
   431
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   432
    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: 36926
diff changeset
   433
    hybriddict() for new template keywords.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   434
    """
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   435
    c = [{key: k, value: v} for k, v in data.iteritems()]
37071
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   436
    f = _showcompatlist(context, mapping, name, c, plural, separator)
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   437
    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: 36926
diff changeset
   438
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   439
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: 36926
diff changeset
   440
               plural=None, separator=' '):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   441
    """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: 36926
diff changeset
   442
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   443
    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: 36926
diff changeset
   444
    hybridlist() for new template keywords.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   445
    """
37071
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   446
    f = _showcompatlist(context, mapping, name, data, plural, separator)
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   447
    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: 36926
diff changeset
   448
37071
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   449
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: 37022
diff changeset
   450
    """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: 37022
diff changeset
   451
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   452
    name is name of key in template map.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   453
    values is list of strings or dicts.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   454
    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: 36926
diff changeset
   455
    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: 36926
diff changeset
   456
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   457
    expansion works like this, given name 'foo'.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   458
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   459
    if values is empty, expand 'no_foos'.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   460
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   461
    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: 36926
diff changeset
   462
    joined by 'separator'.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   463
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   464
    expand 'start_foos'.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   465
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   466
    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: 36926
diff changeset
   467
    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: 36926
diff changeset
   468
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   469
    expand 'end_foos'.
37071
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   470
    """
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   471
    if not plural:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   472
        plural = name + 's'
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   473
    if not values:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   474
        noname = 'no_' + plural
37071
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   475
        if context.preload(noname):
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   476
            yield context.process(noname, mapping)
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   477
        return
37071
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   478
    if not context.preload(name):
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   479
        if isinstance(values[0], bytes):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   480
            yield separator.join(values)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   481
        else:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   482
            for v in values:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   483
                r = dict(v)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   484
                r.update(mapping)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   485
                yield r
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   486
        return
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   487
    startname = 'start_' + plural
37071
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   488
    if context.preload(startname):
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   489
        yield context.process(startname, mapping)
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   490
    def one(v, tag=name):
37077
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37076
diff changeset
   491
        vmapping = {}
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   492
        try:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   493
            vmapping.update(v)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   494
        # 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: 36926
diff changeset
   495
        # 3 raises TypeError.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   496
        except (AttributeError, TypeError, ValueError):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   497
            try:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   498
                # 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: 36926
diff changeset
   499
                # bytes. Python 3 raises TypeError.
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   500
                for a, b in v:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   501
                    vmapping[a] = b
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   502
            except (TypeError, ValueError):
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   503
                vmapping[name] = v
37077
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37076
diff changeset
   504
        vmapping = context.overlaymap(mapping, vmapping)
37071
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   505
        return context.process(tag, vmapping)
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   506
    lastname = 'last_' + name
37071
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   507
    if context.preload(lastname):
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   508
        last = values.pop()
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   509
    else:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   510
        last = None
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   511
    for v in values:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   512
        yield one(v)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   513
    if last is not None:
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   514
        yield one(last, tag=lastname)
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   515
    endname = 'end_' + plural
37071
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   516
    if context.preload(endname):
aa97e06a1912 templater: use template context to render old-style list template
Yuya Nishihara <yuya@tcha.org>
parents: 37022
diff changeset
   517
        yield context.process(endname, mapping)
36927
32f9b7e3f056 templater: move hybrid class and functions to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36926
diff changeset
   518
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   519
def flatten(context, mapping, thing):
37159
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   520
    """Yield a single stream from a possibly nested set of iterators"""
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   521
    thing = unwraphybrid(context, mapping, thing)
37159
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   522
    if isinstance(thing, bytes):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   523
        yield thing
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   524
    elif isinstance(thing, str):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   525
        # 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: 37107
diff changeset
   526
        # against infinite recursion.
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   527
        raise error.ProgrammingError('Mercurial IO including templates is done'
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   528
                                     ' with bytes, not strings, got %r' % thing)
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   529
    elif thing is None:
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   530
        pass
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   531
    elif not util.safehasattr(thing, '__iter__'):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   532
        yield pycompat.bytestr(thing)
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   533
    else:
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   534
        for i in thing:
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   535
            i = unwraphybrid(context, mapping, i)
37159
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   536
            if isinstance(i, bytes):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   537
                yield i
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   538
            elif i is None:
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   539
                pass
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   540
            elif not util.safehasattr(i, '__iter__'):
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   541
                yield pycompat.bytestr(i)
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   542
            else:
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   543
                for j in flatten(context, mapping, i):
37159
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   544
                    yield j
888507ec655e templateutil: move flatten() from templater
Yuya Nishihara <yuya@tcha.org>
parents: 37107
diff changeset
   545
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   546
def stringify(context, mapping, thing):
36926
6ff6e1d6b5b8 templater: move stringify() to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36919
diff changeset
   547
    """Turn values into bytes by converting into text and concatenating them"""
37160
e09d2183e226 templateutil: reimplement stringify() using flatten()
Yuya Nishihara <yuya@tcha.org>
parents: 37159
diff changeset
   548
    if isinstance(thing, bytes):
e09d2183e226 templateutil: reimplement stringify() using flatten()
Yuya Nishihara <yuya@tcha.org>
parents: 37159
diff changeset
   549
        return thing  # retain localstr to be round-tripped
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   550
    return b''.join(flatten(context, mapping, thing))
36926
6ff6e1d6b5b8 templater: move stringify() to templateutil module
Yuya Nishihara <yuya@tcha.org>
parents: 36919
diff changeset
   551
31927
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   552
def findsymbolicname(arg):
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   553
    """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
   554
    if nothing found reliably"""
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   555
    while True:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   556
        func, data = arg
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   557
        if func is runsymbol:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   558
            return data
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   559
        elif func is runfilter:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   560
            arg = data[0]
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   561
        else:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   562
            return None
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   563
37280
671a01cd50b5 templater: extract private function to evaluate generator to byte string
Yuya Nishihara <yuya@tcha.org>
parents: 37279
diff changeset
   564
def _unthunk(context, mapping, thing):
671a01cd50b5 templater: extract private function to evaluate generator to byte string
Yuya Nishihara <yuya@tcha.org>
parents: 37279
diff changeset
   565
    """Evaluate a lazy byte string into value"""
671a01cd50b5 templater: extract private function to evaluate generator to byte string
Yuya Nishihara <yuya@tcha.org>
parents: 37279
diff changeset
   566
    if not isinstance(thing, types.GeneratorType):
671a01cd50b5 templater: extract private function to evaluate generator to byte string
Yuya Nishihara <yuya@tcha.org>
parents: 37279
diff changeset
   567
        return thing
671a01cd50b5 templater: extract private function to evaluate generator to byte string
Yuya Nishihara <yuya@tcha.org>
parents: 37279
diff changeset
   568
    return stringify(context, mapping, thing)
671a01cd50b5 templater: extract private function to evaluate generator to byte string
Yuya Nishihara <yuya@tcha.org>
parents: 37279
diff changeset
   569
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   570
def evalrawexp(context, mapping, arg):
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   571
    """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: 34332
diff changeset
   572
    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
   573
    func, data = arg
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   574
    return func(context, mapping, data)
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   575
38238
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   576
def evalwrapped(context, mapping, arg):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   577
    """Evaluate given argument to wrapped object"""
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   578
    thing = evalrawexp(context, mapping, arg)
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   579
    return makewrapped(context, mapping, thing)
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   580
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   581
def makewrapped(context, mapping, thing):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   582
    """Lift object to a wrapped type"""
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   583
    if isinstance(thing, wrapped):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   584
        return thing
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   585
    thing = _unthunk(context, mapping, thing)
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   586
    if isinstance(thing, bytes):
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   587
        return wrappedbytes(thing)
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   588
    return wrappedvalue(thing)
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38237
diff changeset
   589
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   590
def evalfuncarg(context, mapping, arg):
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   591
    """Evaluate given argument as value type"""
38237
d48b80d58848 templater: unify unwrapvalue() with _unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 38236
diff changeset
   592
    return unwrapvalue(context, mapping, evalrawexp(context, mapping, arg))
37163
0023da2910c9 templater: extract type conversion from evalfuncarg()
Yuya Nishihara <yuya@tcha.org>
parents: 37162
diff changeset
   593
38237
d48b80d58848 templater: unify unwrapvalue() with _unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 38236
diff changeset
   594
def unwrapvalue(context, mapping, thing):
d48b80d58848 templater: unify unwrapvalue() with _unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 38236
diff changeset
   595
    """Move the inner value object out of the wrapper"""
38236
61cecab0cc20 templater: inline unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37502
diff changeset
   596
    if isinstance(thing, wrapped):
61cecab0cc20 templater: inline unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37502
diff changeset
   597
        return thing.tovalue(context, mapping)
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   598
    # 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: 34332
diff changeset
   599
    # such as date tuple, but filter does not want generator.
37280
671a01cd50b5 templater: extract private function to evaluate generator to byte string
Yuya Nishihara <yuya@tcha.org>
parents: 37279
diff changeset
   600
    return _unthunk(context, mapping, thing)
26124
604a7c941103 templater: extract helper that evaluates filter or function argument
Yuya Nishihara <yuya@tcha.org>
parents: 26106
diff changeset
   601
29827
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   602
def evalboolean(context, mapping, arg):
29828
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   603
    """Evaluate given argument as boolean, but also takes boolean literals"""
29827
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   604
    func, data = arg
29828
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   605
    if func is runsymbol:
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   606
        thing = func(context, mapping, data, default=None)
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   607
        if thing is None:
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   608
            # not a template keyword, takes as a boolean literal
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37077
diff changeset
   609
            thing = stringutil.parsebool(data)
29828
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   610
    else:
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   611
        thing = func(context, mapping, data)
38236
61cecab0cc20 templater: inline unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37502
diff changeset
   612
    if isinstance(thing, wrapped):
61cecab0cc20 templater: inline unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 37502
diff changeset
   613
        thing = thing.tovalue(context, mapping)
29827
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   614
    if isinstance(thing, bool):
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   615
        return thing
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   616
    # 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: 29826
diff changeset
   617
    # empty dict/list should be False as they are expected to be ''
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   618
    return bool(stringify(context, mapping, thing))
29827
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   619
37226
67efce231633 templater: factor out function that parses argument as date tuple
Yuya Nishihara <yuya@tcha.org>
parents: 37224
diff changeset
   620
def evaldate(context, mapping, arg, err=None):
67efce231633 templater: factor out function that parses argument as date tuple
Yuya Nishihara <yuya@tcha.org>
parents: 37224
diff changeset
   621
    """Evaluate given argument as a date tuple or a date string; returns
67efce231633 templater: factor out function that parses argument as date tuple
Yuya Nishihara <yuya@tcha.org>
parents: 37224
diff changeset
   622
    a (unixtime, offset) tuple"""
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   623
    thing = evalrawexp(context, mapping, arg)
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   624
    return unwrapdate(context, mapping, thing, err)
37226
67efce231633 templater: factor out function that parses argument as date tuple
Yuya Nishihara <yuya@tcha.org>
parents: 37224
diff changeset
   625
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   626
def unwrapdate(context, mapping, thing, err=None):
38237
d48b80d58848 templater: unify unwrapvalue() with _unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 38236
diff changeset
   627
    thing = unwrapvalue(context, mapping, thing)
37226
67efce231633 templater: factor out function that parses argument as date tuple
Yuya Nishihara <yuya@tcha.org>
parents: 37224
diff changeset
   628
    try:
67efce231633 templater: factor out function that parses argument as date tuple
Yuya Nishihara <yuya@tcha.org>
parents: 37224
diff changeset
   629
        return dateutil.parsedate(thing)
67efce231633 templater: factor out function that parses argument as date tuple
Yuya Nishihara <yuya@tcha.org>
parents: 37224
diff changeset
   630
    except AttributeError:
67efce231633 templater: factor out function that parses argument as date tuple
Yuya Nishihara <yuya@tcha.org>
parents: 37224
diff changeset
   631
        raise error.ParseError(err or _('not a date tuple nor a string'))
37227
e70a90a72b80 templatefuncs: use evaldate() where seems appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 37226
diff changeset
   632
    except error.ParseError:
e70a90a72b80 templatefuncs: use evaldate() where seems appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 37226
diff changeset
   633
        if not err:
e70a90a72b80 templatefuncs: use evaldate() where seems appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 37226
diff changeset
   634
            raise
e70a90a72b80 templatefuncs: use evaldate() where seems appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 37226
diff changeset
   635
        raise error.ParseError(err)
37226
67efce231633 templater: factor out function that parses argument as date tuple
Yuya Nishihara <yuya@tcha.org>
parents: 37224
diff changeset
   636
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
   637
def evalinteger(context, mapping, arg, err=None):
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   638
    thing = evalrawexp(context, mapping, arg)
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   639
    return unwrapinteger(context, mapping, thing, err)
37164
9ab3491f84c2 templater: extract unwrapinteger() function from evalinteger()
Yuya Nishihara <yuya@tcha.org>
parents: 37163
diff changeset
   640
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   641
def unwrapinteger(context, mapping, thing, err=None):
38237
d48b80d58848 templater: unify unwrapvalue() with _unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 38236
diff changeset
   642
    thing = unwrapvalue(context, mapping, thing)
28343
a6c2310b3827 templater: factor out function that evaluates argument as integer
Yuya Nishihara <yuya@tcha.org>
parents: 28334
diff changeset
   643
    try:
37164
9ab3491f84c2 templater: extract unwrapinteger() function from evalinteger()
Yuya Nishihara <yuya@tcha.org>
parents: 37163
diff changeset
   644
        return int(thing)
28344
ac371d4c007f templater: drop redundant type conversion when evaluating integer argument
Yuya Nishihara <yuya@tcha.org>
parents: 28343
diff changeset
   645
    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
   646
        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
   647
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   648
def evalstring(context, mapping, arg):
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   649
    return stringify(context, mapping, 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
   650
28373
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   651
def evalstringliteral(context, mapping, arg):
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   652
    """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
   653
    if it is unknown"""
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   654
    func, data = arg
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   655
    if func is runsymbol:
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   656
        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
   657
    else:
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   658
        thing = func(context, mapping, data)
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   659
    return stringify(context, mapping, thing)
28373
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   660
37165
0fb28899e81a templater: factor out unwrapastype() from evalastype()
Yuya Nishihara <yuya@tcha.org>
parents: 37164
diff changeset
   661
_unwrapfuncbytype = {
38237
d48b80d58848 templater: unify unwrapvalue() with _unwrapvalue()
Yuya Nishihara <yuya@tcha.org>
parents: 38236
diff changeset
   662
    None: unwrapvalue,
37165
0fb28899e81a templater: factor out unwrapastype() from evalastype()
Yuya Nishihara <yuya@tcha.org>
parents: 37164
diff changeset
   663
    bytes: stringify,
37229
9bcf096a2da2 templatefilters: declare input type as date where appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 37228
diff changeset
   664
    date: unwrapdate,
37165
0fb28899e81a templater: factor out unwrapastype() from evalastype()
Yuya Nishihara <yuya@tcha.org>
parents: 37164
diff changeset
   665
    int: unwrapinteger,
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
   666
}
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   667
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   668
def unwrapastype(context, mapping, thing, typ):
37165
0fb28899e81a templater: factor out unwrapastype() from evalastype()
Yuya Nishihara <yuya@tcha.org>
parents: 37164
diff changeset
   669
    """Move the inner value object out of the wrapper and coerce its type"""
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
   670
    try:
37165
0fb28899e81a templater: factor out unwrapastype() from evalastype()
Yuya Nishihara <yuya@tcha.org>
parents: 37164
diff changeset
   671
        f = _unwrapfuncbytype[typ]
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
   672
    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
   673
        raise error.ProgrammingError('invalid type specified: %r' % typ)
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   674
    return f(context, mapping, thing)
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
   675
25002
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   676
def runinteger(context, mapping, data):
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   677
    return int(data)
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   678
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   679
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
   680
    return data
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   681
27939
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   682
def _recursivesymbolblocker(key):
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   683
    def showrecursion(**args):
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   684
        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
   685
    return showrecursion
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   686
28373
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   687
def runsymbol(context, mapping, key, default=''):
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
   688
    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
   689
    if v is None:
27939
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   690
        # 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
   691
        # 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
   692
        safemapping = mapping.copy()
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   693
        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
   694
        try:
27939
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   695
            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
   696
        except TemplateNotFound:
28373
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   697
            v = default
36475
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   698
    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: 36474
diff changeset
   699
        # old templatekw: expand all keywords and resources
37073
1101d6747d2d templater: drop 'templ' from resources dict
Yuya Nishihara <yuya@tcha.org>
parents: 37071
diff changeset
   700
        # (TODO: deprecate this after porting web template keywords to new API)
37076
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   701
        props = {k: context._resources.lookup(context, mapping, k)
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   702
                 for k in context._resources.knownkeys()}
37073
1101d6747d2d templater: drop 'templ' from resources dict
Yuya Nishihara <yuya@tcha.org>
parents: 37071
diff changeset
   703
        # pass context to _showcompatlist() through templatekw._showlist()
1101d6747d2d templater: drop 'templ' from resources dict
Yuya Nishihara <yuya@tcha.org>
parents: 37071
diff changeset
   704
        props['templ'] = context
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
   705
        props.update(mapping)
35588
dadbf213a765 py3: convert dict keys' to str before passing as kwargs
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35485
diff changeset
   706
        return v(**pycompat.strkwargs(props))
36475
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   707
    if callable(v):
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   708
        # new templatekw
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   709
        try:
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   710
            return v(context, mapping)
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   711
        except ResourceUnavailable:
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   712
            # 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: 36474
diff changeset
   713
            return None
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   714
    return v
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   715
25595
a7dd6692e5cb templater: move runtemplate function out of buildmap/runmap pair
Yuya Nishihara <yuya@tcha.org>
parents: 25580
diff changeset
   716
def runtemplate(context, mapping, template):
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   717
    for arg in template:
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   718
        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
   719
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   720
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
   721
    arg, filt = data
37224
54355c243042 templatefilters: allow declaration of input data type
Yuya Nishihara <yuya@tcha.org>
parents: 37165
diff changeset
   722
    thing = evalrawexp(context, mapping, arg)
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   723
    intype = getattr(filt, '_intype', None)
17383
099c778ceb33 templater: abort when a template filter raises an exception (issue2987)
Neil Kodner <neilk@fb.com>
parents: 17334
diff changeset
   724
    try:
37274
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37233
diff changeset
   725
        thing = unwrapastype(context, mapping, thing, intype)
24280
6c55e37ba5f2 templater: allow piping generator-type function output to filters
Yuya Nishihara <yuya@tcha.org>
parents: 24240
diff changeset
   726
        return filt(thing)
37228
920589f52be9 templater: attach hint to input-type error of runfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 37227
diff changeset
   727
    except error.ParseError as e:
920589f52be9 templater: attach hint to input-type error of runfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 37227
diff changeset
   728
        raise error.ParseError(bytes(e), hint=_formatfiltererror(arg, filt))
920589f52be9 templater: attach hint to input-type error of runfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 37227
diff changeset
   729
920589f52be9 templater: attach hint to input-type error of runfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 37227
diff changeset
   730
def _formatfiltererror(arg, filt):
920589f52be9 templater: attach hint to input-type error of runfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 37227
diff changeset
   731
    fn = pycompat.sysbytes(filt.__name__)
920589f52be9 templater: attach hint to input-type error of runfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 37227
diff changeset
   732
    sym = findsymbolicname(arg)
920589f52be9 templater: attach hint to input-type error of runfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 37227
diff changeset
   733
    if not sym:
920589f52be9 templater: attach hint to input-type error of runfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 37227
diff changeset
   734
        return _("incompatible use of template filter '%s'") % fn
920589f52be9 templater: attach hint to input-type error of runfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 37227
diff changeset
   735
    return (_("template filter '%s' is not compatible with keyword '%s'")
920589f52be9 templater: attach hint to input-type error of runfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 37227
diff changeset
   736
            % (fn, sym))
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   737
37399
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   738
def _iteroverlaymaps(context, origmapping, newmappings):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   739
    """Generate combined mappings from the original mapping and an iterable
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   740
    of partial mappings to override the original"""
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   741
    for i, nm in enumerate(newmappings):
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   742
        lm = context.overlaymap(origmapping, nm)
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   743
        lm['index'] = i
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   744
        yield lm
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37329
diff changeset
   745
38241
7701c2d4a438 templater: always map over a wrapped object
Yuya Nishihara <yuya@tcha.org>
parents: 38240
diff changeset
   746
def _applymap(context, mapping, d, targ):
7701c2d4a438 templater: always map over a wrapped object
Yuya Nishihara <yuya@tcha.org>
parents: 38240
diff changeset
   747
    for lm in _iteroverlaymaps(context, mapping, d.itermaps(context)):
37499
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   748
        yield evalrawexp(context, lm, targ)
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37405
diff changeset
   749
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   750
def runmap(context, mapping, data):
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   751
    darg, targ = data
38241
7701c2d4a438 templater: always map over a wrapped object
Yuya Nishihara <yuya@tcha.org>
parents: 38240
diff changeset
   752
    d = evalwrapped(context, mapping, darg)
7701c2d4a438 templater: always map over a wrapped object
Yuya Nishihara <yuya@tcha.org>
parents: 38240
diff changeset
   753
    return mappedgenerator(_applymap, args=(mapping, d, targ))
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   754
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   755
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
   756
    darg, memb = data
38252
c2456a7726c1 templater: do dict lookup over a wrapped object
Yuya Nishihara <yuya@tcha.org>
parents: 38241
diff changeset
   757
    d = evalwrapped(context, mapping, darg)
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   758
    if util.safehasattr(d, 'tomap'):
37077
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37076
diff changeset
   759
        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
   760
        return runsymbol(context, lm, memb)
38253
ad06a4264daf templater: add try-except stub to runmember()
Yuya Nishihara <yuya@tcha.org>
parents: 38252
diff changeset
   761
    try:
38255
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   762
        return d.getmember(context, mapping, memb)
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   763
    except error.ParseError as err:
38253
ad06a4264daf templater: add try-except stub to runmember()
Yuya Nishihara <yuya@tcha.org>
parents: 38252
diff changeset
   764
        sym = findsymbolicname(darg)
38255
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   765
        if not sym:
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   766
            raise
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   767
        hint = _("keyword '%s' does not support member operation") % sym
06d11cd90516 templater: promote getmember() to an interface of wrapped types
Yuya Nishihara <yuya@tcha.org>
parents: 38254
diff changeset
   768
        raise error.ParseError(bytes(err), hint=hint)
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   769
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   770
def runnegate(context, mapping, data):
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   771
    data = evalinteger(context, mapping, data,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   772
                       _('negation needs an integer argument'))
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   773
    return -data
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   774
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   775
def runarithmetic(context, mapping, data):
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   776
    func, left, right = data
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   777
    left = evalinteger(context, mapping, left,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   778
                       _('arithmetic only defined on integers'))
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   779
    right = evalinteger(context, mapping, right,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   780
                        _('arithmetic only defined on integers'))
30116
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   781
    try:
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   782
        return func(left, right)
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   783
    except ZeroDivisionError:
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   784
        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
   785
37325
41a5d815d2c1 templater: factor out generator of join()-ed items
Yuya Nishihara <yuya@tcha.org>
parents: 37324
diff changeset
   786
def joinitems(itemiter, sep):
41a5d815d2c1 templater: factor out generator of join()-ed items
Yuya Nishihara <yuya@tcha.org>
parents: 37324
diff changeset
   787
    """Join items with the separator; Returns generator of bytes"""
41a5d815d2c1 templater: factor out generator of join()-ed items
Yuya Nishihara <yuya@tcha.org>
parents: 37324
diff changeset
   788
    first = True
41a5d815d2c1 templater: factor out generator of join()-ed items
Yuya Nishihara <yuya@tcha.org>
parents: 37324
diff changeset
   789
    for x in itemiter:
41a5d815d2c1 templater: factor out generator of join()-ed items
Yuya Nishihara <yuya@tcha.org>
parents: 37324
diff changeset
   790
        if first:
41a5d815d2c1 templater: factor out generator of join()-ed items
Yuya Nishihara <yuya@tcha.org>
parents: 37324
diff changeset
   791
            first = False
37326
9cd88dd3bf64 templater: micro-optimize join() with empty separator
Yuya Nishihara <yuya@tcha.org>
parents: 37325
diff changeset
   792
        elif sep:
37325
41a5d815d2c1 templater: factor out generator of join()-ed items
Yuya Nishihara <yuya@tcha.org>
parents: 37324
diff changeset
   793
            yield sep
41a5d815d2c1 templater: factor out generator of join()-ed items
Yuya Nishihara <yuya@tcha.org>
parents: 37324
diff changeset
   794
        yield x