mercurial/templater.py
author Boris Feld <boris.feld@octobus.net>
Thu, 15 Feb 2018 17:18:26 +0100
changeset 36636 c6061cadb400
parent 36625 b5d39a09656a
child 36676 052351e3e1cd
permissions -rw-r--r--
util: extract all date-related utils in utils/dateutil module With this commit, util.py lose 262 lines Note for extensions author, if this commit breaks your extension, you can pull the step-by-step split here to help you more easily pinpoint the renaming that broke your extension: hg pull https://bitbucket.org/octobus/mercurial-devel/ -r ac1f6453010d Differential Revision: https://phab.mercurial-scm.org/D2282
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1909
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
     1
# templater.py - template expansion for output
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
34152
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34146
diff changeset
     8
from __future__ import absolute_import, print_function
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
     9
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    10
import os
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    11
import re
17982
e06e9fd2d99f template engine: convert generator-based iterator to list-based iterator
Weiwen <weiwen@fb.com>
parents: 17890
diff changeset
    12
import types
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    13
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    14
from .i18n import _
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    15
from . import (
31527
44c591f63458 templater: make pad() strip color codes before computing width (issue5416)
Yuya Nishihara <yuya@tcha.org>
parents: 31526
diff changeset
    16
    color,
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    17
    config,
31526
6f150bb19317 templater: make pad() compute actual width
Yuya Nishihara <yuya@tcha.org>
parents: 31525
diff changeset
    18
    encoding,
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    19
    error,
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    20
    minirst,
34011
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
    21
    obsutil,
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    22
    parser,
30620
bb77654dc7ae py3: replace os.sep with pycompat.ossep (part 3 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30342
diff changeset
    23
    pycompat,
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
    24
    registrar,
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    25
    revset as revsetmod,
31044
0b8356705de6 revset: split language services to revsetlang module (API)
Yuya Nishihara <yuya@tcha.org>
parents: 30630
diff changeset
    26
    revsetlang,
34459
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
    27
    scmutil,
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    28
    templatefilters,
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    29
    templatekw,
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    30
    util,
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    31
)
36636
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36625
diff changeset
    32
from .utils import dateutil
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    33
36474
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36473
diff changeset
    34
class ResourceUnavailable(error.Abort):
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36473
diff changeset
    35
    pass
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36473
diff changeset
    36
36473
8dbd97aef915 templater: move specialized exception types to top
Yuya Nishihara <yuya@tcha.org>
parents: 36278
diff changeset
    37
class TemplateNotFound(error.Abort):
8dbd97aef915 templater: move specialized exception types to top
Yuya Nishihara <yuya@tcha.org>
parents: 36278
diff changeset
    38
    pass
8dbd97aef915 templater: move specialized exception types to top
Yuya Nishihara <yuya@tcha.org>
parents: 36278
diff changeset
    39
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    40
# template parsing
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    41
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    42
elements = {
25815
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    43
    # token-type: binding-strength, primary, prefix, infix, suffix
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    44
    "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
    45
    ".": (18, None, None, (".", 18), None),
34336
6367318327f0 templater: adjust binding strength of '%' and '|' operators (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 34335
diff changeset
    46
    "%": (15, None, None, ("%", 15), None),
31884
0926ca37a990 templater: adjust binding strengths to make room for key-value operator
Yuya Nishihara <yuya@tcha.org>
parents: 31883
diff changeset
    47
    "|": (15, None, None, ("|", 15), None),
0926ca37a990 templater: adjust binding strengths to make room for key-value operator
Yuya Nishihara <yuya@tcha.org>
parents: 31883
diff changeset
    48
    "*": (5, None, None, ("*", 5), None),
0926ca37a990 templater: adjust binding strengths to make room for key-value operator
Yuya Nishihara <yuya@tcha.org>
parents: 31883
diff changeset
    49
    "/": (5, None, None, ("/", 5), None),
0926ca37a990 templater: adjust binding strengths to make room for key-value operator
Yuya Nishihara <yuya@tcha.org>
parents: 31883
diff changeset
    50
    "+": (4, None, None, ("+", 4), None),
0926ca37a990 templater: adjust binding strengths to make room for key-value operator
Yuya Nishihara <yuya@tcha.org>
parents: 31883
diff changeset
    51
    "-": (4, None, ("negate", 19), ("-", 4), None),
31885
d18b624c1c06 templater: add parsing rule for key-value pair
Yuya Nishihara <yuya@tcha.org>
parents: 31884
diff changeset
    52
    "=": (3, None, None, ("keyvalue", 3), None),
31883
25be03a33f50 templater: sort token table by binding strength
Yuya Nishihara <yuya@tcha.org>
parents: 31880
diff changeset
    53
    ",": (2, None, None, ("list", 2), None),
25be03a33f50 templater: sort token table by binding strength
Yuya Nishihara <yuya@tcha.org>
parents: 31880
diff changeset
    54
    ")": (0, None, None, None, None),
25815
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    55
    "integer": (0, "integer", None, None, None),
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    56
    "symbol": (0, "symbol", None, None, None),
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    57
    "string": (0, "string", None, None, None),
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    58
    "template": (0, "template", None, None, None),
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    59
    "end": (0, None, None, None, None),
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    60
}
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    61
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
    62
def tokenize(program, start, end, term=None):
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
    63
    """Parse a template expression into a stream of tokens, which must end
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
    64
    with term if specified"""
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    65
    pos = start
32203
52e222eef646 py3: use pycompat.bytestr instead of bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32037
diff changeset
    66
    program = pycompat.bytestr(program)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    67
    while pos < end:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    68
        c = program[pos]
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    69
        if c.isspace(): # skip inter-token whitespace
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    70
            pass
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
    71
        elif c in "(=,).%|+-*/": # handle simple operators
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    72
            yield (c, None, pos)
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
    73
        elif c in '"\'': # handle quoted templates
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
    74
            s = pos + 1
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
    75
            data, pos = _parsetemplate(program, s, end, c)
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
    76
            yield ('template', data, s)
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
    77
            pos -= 1
25784
33e613687dab templater: remove processing of "string" literals from tokenizer
Yuya Nishihara <yuya@tcha.org>
parents: 25783
diff changeset
    78
        elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
33e613687dab templater: remove processing of "string" literals from tokenizer
Yuya Nishihara <yuya@tcha.org>
parents: 25783
diff changeset
    79
            # handle quoted strings
33e613687dab templater: remove processing of "string" literals from tokenizer
Yuya Nishihara <yuya@tcha.org>
parents: 25783
diff changeset
    80
            c = program[pos + 1]
33e613687dab templater: remove processing of "string" literals from tokenizer
Yuya Nishihara <yuya@tcha.org>
parents: 25783
diff changeset
    81
            s = pos = pos + 2
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    82
            while pos < end: # find closing quote
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    83
                d = program[pos]
25638
6047b60cdd09 templater: fix handling of \-escapes in raw string literals
Yuya Nishihara <yuya@tcha.org>
parents: 25637
diff changeset
    84
                if d == '\\': # skip over escaped characters
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    85
                    pos += 2
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    86
                    continue
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    87
                if d == c:
25785
f976b7dc5e7b templater: unify "string" and "rawstring"
Yuya Nishihara <yuya@tcha.org>
parents: 25784
diff changeset
    88
                    yield ('string', program[s:pos], s)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    89
                    break
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    90
                pos += 1
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    91
            else:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    92
                raise error.ParseError(_("unterminated string"), s)
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
    93
        elif c.isdigit():
25002
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
    94
            s = pos
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
    95
            while pos < end:
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
    96
                d = program[pos]
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
    97
                if not d.isdigit():
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
    98
                    break
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
    99
                pos += 1
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   100
            yield ('integer', program[s:pos], s)
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   101
            pos -= 1
36575
14bbb54a9c5b py3: fix type of string literals in templater.tokenize()
Yuya Nishihara <yuya@tcha.org>
parents: 36574
diff changeset
   102
        elif (c == '\\' and program[pos:pos + 2] in (br"\'", br'\"')
14bbb54a9c5b py3: fix type of string literals in templater.tokenize()
Yuya Nishihara <yuya@tcha.org>
parents: 36574
diff changeset
   103
              or c == 'r' and program[pos:pos + 3] in (br"r\'", br'r\"')):
25676
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   104
            # handle escaped quoted strings for compatibility with 2.9.2-3.4,
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   105
            # where some of nested templates were preprocessed as strings and
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   106
            # then compiled. therefore, \"...\" was allowed. (issue4733)
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   107
            #
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   108
            # processing flow of _evalifliteral() at 5ab28a2e9962:
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   109
            # outer template string    -> stringify()  -> compiletemplate()
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   110
            # ------------------------    ------------    ------------------
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   111
            # {f("\\\\ {g(\"\\\"\")}"}    \\ {g("\"")}    [r'\\', {g("\"")}]
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   112
            #             ~~~~~~~~
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   113
            #             escaped quoted string
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   114
            if c == 'r':
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   115
                pos += 1
25785
f976b7dc5e7b templater: unify "string" and "rawstring"
Yuya Nishihara <yuya@tcha.org>
parents: 25784
diff changeset
   116
                token = 'string'
25676
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   117
            else:
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   118
                token = 'template'
25676
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   119
            quote = program[pos:pos + 2]
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   120
            s = pos = pos + 2
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   121
            while pos < end: # find closing escaped quote
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   122
                if program.startswith('\\\\\\', pos, end):
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   123
                    pos += 4 # skip over double escaped characters
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   124
                    continue
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   125
                if program.startswith(quote, pos, end):
26215
72aad184f061 templater: create string unescape helper (issue4798)
Matt Mackall <mpm@selenic.com>
parents: 26197
diff changeset
   126
                    # interpret as if it were a part of an outer string
26231
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 26215
diff changeset
   127
                    data = parser.unescapestr(program[s:pos])
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   128
                    if token == 'template':
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   129
                        data = _parsetemplate(data, 0, len(data))[0]
25676
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   130
                    yield (token, data, s)
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   131
                    pos += 1
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   132
                    break
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   133
                pos += 1
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   134
            else:
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   135
                raise error.ParseError(_("unterminated string"), s)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   136
        elif c.isalnum() or c in '_':
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   137
            s = pos
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   138
            pos += 1
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   139
            while pos < end: # find end of symbol
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   140
                d = program[pos]
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   141
                if not (d.isalnum() or d == "_"):
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   142
                    break
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   143
                pos += 1
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   144
            sym = program[s:pos]
18893
74ea61318ea8 templater: back out 0615b22da148, it breaks schemes ({1})
Brendan Cully <brendan@kublai.com>
parents: 18889
diff changeset
   145
            yield ('symbol', sym, s)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   146
            pos -= 1
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   147
        elif c == term:
25782
babd2c93bd99 templater: check existence of closing brace of template string
Yuya Nishihara <yuya@tcha.org>
parents: 25781
diff changeset
   148
            yield ('end', None, pos + 1)
babd2c93bd99 templater: check existence of closing brace of template string
Yuya Nishihara <yuya@tcha.org>
parents: 25781
diff changeset
   149
            return
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   150
        else:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   151
            raise error.ParseError(_("syntax error"), pos)
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   152
        pos += 1
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   153
    if term:
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   154
        raise error.ParseError(_("unterminated template expansion"), start)
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   155
    yield ('end', None, pos)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   156
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   157
def _parsetemplate(tmpl, start, stop, quote=''):
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   158
    r"""
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   159
    >>> _parsetemplate(b'foo{bar}"baz', 0, 12)
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   160
    ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   161
    >>> _parsetemplate(b'foo{bar}"baz', 0, 12, quote=b'"')
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   162
    ([('string', 'foo'), ('symbol', 'bar')], 9)
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   163
    >>> _parsetemplate(b'foo"{bar}', 0, 9, quote=b'"')
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   164
    ([('string', 'foo')], 4)
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   165
    >>> _parsetemplate(br'foo\"bar"baz', 0, 12, quote=b'"')
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   166
    ([('string', 'foo"'), ('string', 'bar')], 9)
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   167
    >>> _parsetemplate(br'foo\\"bar', 0, 10, quote=b'"')
25785
f976b7dc5e7b templater: unify "string" and "rawstring"
Yuya Nishihara <yuya@tcha.org>
parents: 25784
diff changeset
   168
    ([('string', 'foo\\')], 6)
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   169
    """
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   170
    parsed = []
36277
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   171
    for typ, val, pos in _scantemplate(tmpl, start, stop, quote):
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   172
        if typ == 'string':
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   173
            parsed.append((typ, val))
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   174
        elif typ == 'template':
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   175
            parsed.append(val)
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   176
        elif typ == 'end':
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   177
            return parsed, pos
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   178
        else:
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   179
            raise error.ProgrammingError('unexpected type: %s' % typ)
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   180
    raise error.ProgrammingError('unterminated scanning of template')
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   181
36539
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   182
def scantemplate(tmpl, raw=False):
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   183
    r"""Scan (type, start, end) positions of outermost elements in template
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   184
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   185
    If raw=True, a backslash is not taken as an escape character just like
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   186
    r'' string in Python. Note that this is different from r'' literal in
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   187
    template in that no template fragment can appear in r'', e.g. r'{foo}'
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   188
    is a literal '{foo}', but ('{foo}', raw=True) is a template expression
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   189
    'foo'.
36278
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   190
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   191
    >>> list(scantemplate(b'foo{bar}"baz'))
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   192
    [('string', 0, 3), ('template', 3, 8), ('string', 8, 12)]
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   193
    >>> list(scantemplate(b'outer{"inner"}outer'))
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   194
    [('string', 0, 5), ('template', 5, 14), ('string', 14, 19)]
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   195
    >>> list(scantemplate(b'foo\\{escaped}'))
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   196
    [('string', 0, 5), ('string', 5, 13)]
36539
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   197
    >>> list(scantemplate(b'foo\\{escaped}', raw=True))
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   198
    [('string', 0, 4), ('template', 4, 13)]
36278
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   199
    """
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   200
    last = None
36539
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   201
    for typ, val, pos in _scantemplate(tmpl, 0, len(tmpl), raw=raw):
36278
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   202
        if last:
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   203
            yield last + (pos,)
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   204
        if typ == 'end':
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   205
            return
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   206
        else:
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   207
            last = (typ, pos)
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   208
    raise error.ProgrammingError('unterminated scanning of template')
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36277
diff changeset
   209
36539
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   210
def _scantemplate(tmpl, start, stop, quote='', raw=False):
36277
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   211
    """Parse template string into chunks of strings and template expressions"""
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   212
    sepchars = '{' + quote
36539
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   213
    unescape = [parser.unescapestr, pycompat.identity][raw]
25781
82c918509ef5 templater: extract function that parses template string
Yuya Nishihara <yuya@tcha.org>
parents: 25780
diff changeset
   214
    pos = start
25654
af329a84310c parser: accept iterator of tokens instead of tokenizer function and program
Yuya Nishihara <yuya@tcha.org>
parents: 25599
diff changeset
   215
    p = parser.parser(elements)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   216
    while pos < stop:
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   217
        n = min((tmpl.find(c, pos, stop) for c in sepchars),
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   218
                key=lambda n: (n < 0, n))
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   219
        if n < 0:
36539
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   220
            yield ('string', unescape(tmpl[pos:stop]), pos)
25780
8b900b937e1c templater: respect stop position while parsing template string
Yuya Nishihara <yuya@tcha.org>
parents: 25696
diff changeset
   221
            pos = stop
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   222
            break
34088
f55769e41803 py3: use bytes[n:n + 1] to get bytes in templater._parsetemplate()
Yuya Nishihara <yuya@tcha.org>
parents: 34013
diff changeset
   223
        c = tmpl[n:n + 1]
36539
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   224
        bs = 0  # count leading backslashes
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   225
        if not raw:
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   226
            bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
25598
55c2cb65bdfa templater: drop strtoken argument from compiletemplate()
Yuya Nishihara <yuya@tcha.org>
parents: 25597
diff changeset
   227
        if bs % 2 == 1:
55c2cb65bdfa templater: drop strtoken argument from compiletemplate()
Yuya Nishihara <yuya@tcha.org>
parents: 25597
diff changeset
   228
            # escaped (e.g. '\{', '\\\{', but not '\\{')
36539
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   229
            yield ('string', unescape(tmpl[pos:n - 1]) + c, pos)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   230
            pos = n + 1
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   231
            continue
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   232
        if n > pos:
36539
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36530
diff changeset
   233
            yield ('string', unescape(tmpl[pos:n]), pos)
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   234
        if c == quote:
36277
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   235
            yield ('end', None, n + 1)
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   236
            return
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   237
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   238
        parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
35680
077ee15b8493 templater: make sure expression is terminated by '}'
Yuya Nishihara <yuya@tcha.org>
parents: 35588
diff changeset
   239
        if not tmpl.endswith('}', n + 1, pos):
077ee15b8493 templater: make sure expression is terminated by '}'
Yuya Nishihara <yuya@tcha.org>
parents: 35588
diff changeset
   240
            raise error.ParseError(_("invalid token"), pos)
36277
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   241
        yield ('template', parseres, n)
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   242
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   243
    if quote:
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   244
        raise error.ParseError(_("unterminated string"), start)
36277
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   245
    yield ('end', None, pos)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   246
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   247
def _unnesttemplatelist(tree):
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   248
    """Expand list of templates to node tuple
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   249
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   250
    >>> def f(tree):
34152
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34146
diff changeset
   251
    ...     print(pycompat.sysstr(prettyformat(_unnesttemplatelist(tree))))
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   252
    >>> f((b'template', []))
34090
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34088
diff changeset
   253
    (string '')
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   254
    >>> f((b'template', [(b'string', b'foo')]))
34090
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34088
diff changeset
   255
    (string 'foo')
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   256
    >>> f((b'template', [(b'string', b'foo'), (b'symbol', b'rev')]))
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   257
    (template
34090
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34088
diff changeset
   258
      (string 'foo')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34088
diff changeset
   259
      (symbol 'rev'))
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   260
    >>> f((b'template', [(b'symbol', b'rev')]))  # template(rev) -> str
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   261
    (template
34090
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34088
diff changeset
   262
      (symbol 'rev'))
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   263
    >>> f((b'template', [(b'template', [(b'string', b'foo')])]))
34090
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34088
diff changeset
   264
    (string 'foo')
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   265
    """
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   266
    if not isinstance(tree, tuple):
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   267
        return tree
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   268
    op = tree[0]
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   269
    if op != 'template':
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   270
        return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   271
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   272
    assert len(tree) == 2
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   273
    xs = tuple(_unnesttemplatelist(x) for x in tree[1])
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   274
    if not xs:
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   275
        return ('string', '')  # empty template ""
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   276
    elif len(xs) == 1 and xs[0][0] == 'string':
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   277
        return xs[0]  # fast path for string with no template fragment "x"
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   278
    else:
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   279
        return (op,) + xs
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   280
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   281
def parse(tmpl):
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   282
    """Parse template string into tree"""
25781
82c918509ef5 templater: extract function that parses template string
Yuya Nishihara <yuya@tcha.org>
parents: 25780
diff changeset
   283
    parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   284
    assert pos == len(tmpl), 'unquoted template should be consumed'
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   285
    return _unnesttemplatelist(('template', parsed))
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   286
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   287
def _parseexpr(expr):
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   288
    """Parse a template expression into tree
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   289
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   290
    >>> _parseexpr(b'"foo"')
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   291
    ('string', 'foo')
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   292
    >>> _parseexpr(b'foo(bar)')
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   293
    ('func', ('symbol', 'foo'), ('symbol', 'bar'))
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   294
    >>> _parseexpr(b'foo(')
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   295
    Traceback (most recent call last):
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   296
      ...
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   297
    ParseError: ('not a prefix: end', 4)
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   298
    >>> _parseexpr(b'"foo" "bar"')
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   299
    Traceback (most recent call last):
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   300
      ...
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   301
    ParseError: ('invalid token', 7)
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   302
    """
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   303
    p = parser.parser(elements)
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   304
    tree, pos = p.parse(tokenize(expr, 0, len(expr)))
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   305
    if pos != len(expr):
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   306
        raise error.ParseError(_('invalid token'), pos)
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   307
    return _unnesttemplatelist(tree)
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   308
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   309
def prettyformat(tree):
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   310
    return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   311
25001
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
   312
def compileexp(exp, context, curmethods):
28956
eea98190ed73 templater: inline compiletemplate() function into engine
Yuya Nishihara <yuya@tcha.org>
parents: 28954
diff changeset
   313
    """Compile parsed template tree to (func, data) pair"""
35744
8685192a8733 templater: fix crash by empty group expression
Yuya Nishihara <yuya@tcha.org>
parents: 35680
diff changeset
   314
    if not exp:
8685192a8733 templater: fix crash by empty group expression
Yuya Nishihara <yuya@tcha.org>
parents: 35680
diff changeset
   315
        raise error.ParseError(_("missing argument"))
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   316
    t = exp[0]
25001
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
   317
    if t in curmethods:
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
   318
        return curmethods[t](exp, context)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   319
    raise error.ParseError(_("unknown method '%s'") % t)
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   320
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   321
# template evaluation
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   322
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   323
def getsymbol(exp):
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   324
    if exp[0] == 'symbol':
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   325
        return exp[1]
21822
028a48105191 templater: add symbol to error
Ryan McElroy <rmcelroy@fb.com>
parents: 21821
diff changeset
   326
    raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   327
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   328
def getlist(x):
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   329
    if not x:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   330
        return []
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   331
    if x[0] == 'list':
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   332
        return getlist(x[1]) + [x[2]]
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   333
    return [x]
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   334
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   335
def gettemplate(exp, context):
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   336
    """Compile given template tree or load named template from map file;
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   337
    returns (func, data) pair"""
28546
1987ed32efca templater: relax type of mapped template
Yuya Nishihara <yuya@tcha.org>
parents: 28545
diff changeset
   338
    if exp[0] in ('template', 'string'):
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   339
        return compileexp(exp, context, methods)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   340
    if exp[0] == 'symbol':
25599
695b93a79d17 templater: comment that gettemplate() has different name resolution order
Yuya Nishihara <yuya@tcha.org>
parents: 25598
diff changeset
   341
        # unlike runsymbol(), here 'symbol' is always taken as template name
695b93a79d17 templater: comment that gettemplate() has different name resolution order
Yuya Nishihara <yuya@tcha.org>
parents: 25598
diff changeset
   342
        # even if it exists in mapping. this allows us to override mapping
695b93a79d17 templater: comment that gettemplate() has different name resolution order
Yuya Nishihara <yuya@tcha.org>
parents: 25598
diff changeset
   343
        # by web templates, e.g. 'changelogtag' is redefined in map file.
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   344
        return context._load(exp[1])
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   345
    raise error.ParseError(_("expected template specifier"))
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   346
31927
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   347
def findsymbolicname(arg):
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   348
    """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
   349
    if nothing found reliably"""
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   350
    while True:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   351
        func, data = arg
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   352
        if func is runsymbol:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   353
            return data
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   354
        elif func is runfilter:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   355
            arg = data[0]
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   356
        else:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   357
            return None
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   358
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   359
def evalrawexp(context, mapping, arg):
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   360
    """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
   361
    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
   362
    func, data = arg
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   363
    return func(context, mapping, data)
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   364
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   365
def evalfuncarg(context, mapping, arg):
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   366
    """Evaluate given argument as value type"""
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   367
    thing = evalrawexp(context, mapping, arg)
34337
89aec1834a86 templatekw: add new-style template expansion to {manifest}
Yuya Nishihara <yuya@tcha.org>
parents: 34336
diff changeset
   368
    thing = templatekw.unwrapvalue(thing)
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   369
    # 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
   370
    # such as date tuple, but filter does not want generator.
26124
604a7c941103 templater: extract helper that evaluates filter or function argument
Yuya Nishihara <yuya@tcha.org>
parents: 26106
diff changeset
   371
    if isinstance(thing, types.GeneratorType):
604a7c941103 templater: extract helper that evaluates filter or function argument
Yuya Nishihara <yuya@tcha.org>
parents: 26106
diff changeset
   372
        thing = stringify(thing)
604a7c941103 templater: extract helper that evaluates filter or function argument
Yuya Nishihara <yuya@tcha.org>
parents: 26106
diff changeset
   373
    return thing
604a7c941103 templater: extract helper that evaluates filter or function argument
Yuya Nishihara <yuya@tcha.org>
parents: 26106
diff changeset
   374
29827
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   375
def evalboolean(context, mapping, arg):
29828
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   376
    """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
   377
    func, data = arg
29828
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   378
    if func is runsymbol:
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   379
        thing = func(context, mapping, data, default=None)
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   380
        if thing is None:
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   381
            # not a template keyword, takes as a boolean literal
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   382
            thing = util.parsebool(data)
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   383
    else:
cc11079644fc templater: make pad() evaluate boolean argument (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 29827
diff changeset
   384
        thing = func(context, mapping, data)
34337
89aec1834a86 templatekw: add new-style template expansion to {manifest}
Yuya Nishihara <yuya@tcha.org>
parents: 34336
diff changeset
   385
    thing = templatekw.unwrapvalue(thing)
29827
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   386
    if isinstance(thing, bool):
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   387
        return thing
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   388
    # 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
   389
    # empty dict/list should be False as they are expected to be ''
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   390
    return bool(stringify(thing))
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   391
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
   392
def evalinteger(context, mapping, arg, err=None):
28344
ac371d4c007f templater: drop redundant type conversion when evaluating integer argument
Yuya Nishihara <yuya@tcha.org>
parents: 28343
diff changeset
   393
    v = evalfuncarg(context, mapping, arg)
28343
a6c2310b3827 templater: factor out function that evaluates argument as integer
Yuya Nishihara <yuya@tcha.org>
parents: 28334
diff changeset
   394
    try:
28344
ac371d4c007f templater: drop redundant type conversion when evaluating integer argument
Yuya Nishihara <yuya@tcha.org>
parents: 28343
diff changeset
   395
        return int(v)
ac371d4c007f templater: drop redundant type conversion when evaluating integer argument
Yuya Nishihara <yuya@tcha.org>
parents: 28343
diff changeset
   396
    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
   397
        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
   398
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   399
def evalstring(context, mapping, arg):
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   400
    return stringify(evalrawexp(context, mapping, arg))
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   401
28373
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   402
def evalstringliteral(context, mapping, arg):
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   403
    """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
   404
    if it is unknown"""
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   405
    func, data = arg
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   406
    if func is runsymbol:
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   407
        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
   408
    else:
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   409
        thing = func(context, mapping, data)
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   410
    return stringify(thing)
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   411
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
   412
_evalfuncbytype = {
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   413
    bool: evalboolean,
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   414
    bytes: evalstring,
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   415
    int: evalinteger,
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   416
}
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   417
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   418
def evalastype(context, mapping, arg, typ):
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   419
    """Evaluate given argument and coerce its type"""
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   420
    try:
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   421
        f = _evalfuncbytype[typ]
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   422
    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
   423
        raise error.ProgrammingError('invalid type specified: %r' % typ)
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   424
    return f(context, mapping, arg)
ee0d74083a22 templater: store revisions as ints so min/max won't compare them as strings
Yuya Nishihara <yuya@tcha.org>
parents: 34536
diff changeset
   425
25002
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   426
def runinteger(context, mapping, data):
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   427
    return int(data)
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   428
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   429
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
   430
    return data
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   431
27939
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   432
def _recursivesymbolblocker(key):
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   433
    def showrecursion(**args):
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   434
        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
   435
    return showrecursion
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   436
27940
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
   437
def _runrecursivesymbol(context, mapping, key):
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
   438
    raise error.Abort(_("recursive reference '%s' in template") % key)
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
   439
28373
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   440
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
   441
    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
   442
    if v is None:
27939
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   443
        # 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
   444
        # 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
   445
        safemapping = mapping.copy()
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   446
        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
   447
        try:
27939
7ed3a3c0cef1 templater: abort if infinite recursion detected while evaluation (issue4758)
Yuya Nishihara <yuya@tcha.org>
parents: 27892
diff changeset
   448
            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
   449
        except TemplateNotFound:
28373
9a9dd71e882c templater: make label() take unknown symbol as color literal
Yuya Nishihara <yuya@tcha.org>
parents: 28349
diff changeset
   450
            v = default
36475
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   451
    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
   452
        # old templatekw: expand all keywords and resources
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
   453
        props = context._resources.copy()
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
   454
        props.update(mapping)
35588
dadbf213a765 py3: convert dict keys' to str before passing as kwargs
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35485
diff changeset
   455
        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
   456
    if callable(v):
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   457
        # new templatekw
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   458
        try:
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   459
            return v(context, mapping)
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   460
        except ResourceUnavailable:
e8d37838f5df templatekw: add 'requires' flag to switch to exception-safe interface
Yuya Nishihara <yuya@tcha.org>
parents: 36474
diff changeset
   461
            # 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
   462
            return None
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   463
    return v
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   464
25596
c1975809a6b5 templater: take any string literals as template, but not for rawstring (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25595
diff changeset
   465
def buildtemplate(exp, context):
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   466
    ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
25596
c1975809a6b5 templater: take any string literals as template, but not for rawstring (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25595
diff changeset
   467
    return (runtemplate, ctmpl)
c1975809a6b5 templater: take any string literals as template, but not for rawstring (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25595
diff changeset
   468
25595
a7dd6692e5cb templater: move runtemplate function out of buildmap/runmap pair
Yuya Nishihara <yuya@tcha.org>
parents: 25580
diff changeset
   469
def runtemplate(context, mapping, template):
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   470
    for arg in template:
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   471
        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
   472
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   473
def buildfilter(exp, context):
26104
0f1bc7faa50d templater: inline getfilter() to buildfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 25985
diff changeset
   474
    n = getsymbol(exp[2])
0f1bc7faa50d templater: inline getfilter() to buildfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 25985
diff changeset
   475
    if n in context._filters:
0f1bc7faa50d templater: inline getfilter() to buildfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 25985
diff changeset
   476
        filt = context._filters[n]
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   477
        arg = compileexp(exp[1], context, methods)
26125
c990afab2243 templater: drop unneeded destructuring of argument tuple at buildfilter
Yuya Nishihara <yuya@tcha.org>
parents: 26124
diff changeset
   478
        return (runfilter, (arg, filt))
26105
d67341f55429 templater: introduce unified filter syntax for unary functions
Yuya Nishihara <yuya@tcha.org>
parents: 26104
diff changeset
   479
    if n in funcs:
d67341f55429 templater: introduce unified filter syntax for unary functions
Yuya Nishihara <yuya@tcha.org>
parents: 26104
diff changeset
   480
        f = funcs[n]
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   481
        args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   482
        return (f, args)
26104
0f1bc7faa50d templater: inline getfilter() to buildfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 25985
diff changeset
   483
    raise error.ParseError(_("unknown function '%s'") % n)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   484
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   485
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
   486
    arg, filt = data
c990afab2243 templater: drop unneeded destructuring of argument tuple at buildfilter
Yuya Nishihara <yuya@tcha.org>
parents: 26124
diff changeset
   487
    thing = evalfuncarg(context, mapping, arg)
17383
099c778ceb33 templater: abort when a template filter raises an exception (issue2987)
Neil Kodner <neilk@fb.com>
parents: 17334
diff changeset
   488
    try:
24280
6c55e37ba5f2 templater: allow piping generator-type function output to filters
Yuya Nishihara <yuya@tcha.org>
parents: 24240
diff changeset
   489
        return filt(thing)
17383
099c778ceb33 templater: abort when a template filter raises an exception (issue2987)
Neil Kodner <neilk@fb.com>
parents: 17334
diff changeset
   490
    except (ValueError, AttributeError, TypeError):
31927
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   491
        sym = findsymbolicname(arg)
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   492
        if sym:
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   493
            msg = (_("template filter '%s' is not compatible with keyword '%s'")
34838
d3ea6a1c798f templater: use pycompat.sysbytes to bytes-ify some __name__ attrs
Augie Fackler <augie@google.com>
parents: 34808
diff changeset
   494
                   % (pycompat.sysbytes(filt.__name__), sym))
17383
099c778ceb33 templater: abort when a template filter raises an exception (issue2987)
Neil Kodner <neilk@fb.com>
parents: 17334
diff changeset
   495
        else:
34838
d3ea6a1c798f templater: use pycompat.sysbytes to bytes-ify some __name__ attrs
Augie Fackler <augie@google.com>
parents: 34808
diff changeset
   496
            msg = (_("incompatible use of template filter '%s'")
d3ea6a1c798f templater: use pycompat.sysbytes to bytes-ify some __name__ attrs
Augie Fackler <augie@google.com>
parents: 34808
diff changeset
   497
                   % pycompat.sysbytes(filt.__name__))
31927
2abc556dbe92 templater: find keyword name more thoroughly on filtering error
Yuya Nishihara <yuya@tcha.org>
parents: 31926
diff changeset
   498
        raise error.Abort(msg)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   499
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   500
def buildmap(exp, context):
34332
86d050abd5c1 templater: do not destructure operands in buildmap()
Yuya Nishihara <yuya@tcha.org>
parents: 34331
diff changeset
   501
    darg = compileexp(exp[1], context, methods)
86d050abd5c1 templater: do not destructure operands in buildmap()
Yuya Nishihara <yuya@tcha.org>
parents: 34331
diff changeset
   502
    targ = gettemplate(exp[2], context)
86d050abd5c1 templater: do not destructure operands in buildmap()
Yuya Nishihara <yuya@tcha.org>
parents: 34331
diff changeset
   503
    return (runmap, (darg, targ))
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   504
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   505
def runmap(context, mapping, data):
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   506
    darg, targ = data
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   507
    d = evalrawexp(context, mapping, darg)
27891
ac8c0ee5c3b8 templater: make _hybrid not callable to avoid conflicting semantics
Yuya Nishihara <yuya@tcha.org>
parents: 27637
diff changeset
   508
    if util.safehasattr(d, 'itermaps'):
28349
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   509
        diter = d.itermaps()
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   510
    else:
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   511
        try:
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   512
            diter = iter(d)
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   513
        except TypeError:
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   514
            sym = findsymbolicname(darg)
34331
e473f482b9b3 templater: use helper function to get name of non-iterable keyword
Yuya Nishihara <yuya@tcha.org>
parents: 34294
diff changeset
   515
            if sym:
e473f482b9b3 templater: use helper function to get name of non-iterable keyword
Yuya Nishihara <yuya@tcha.org>
parents: 34294
diff changeset
   516
                raise error.ParseError(_("keyword '%s' is not iterable") % sym)
28349
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   517
            else:
7cb2f2438f85 templater: handle exception when applying map operator to non-iterable object
Yuya Nishihara <yuya@tcha.org>
parents: 28348
diff changeset
   518
                raise error.ParseError(_("%r is not iterable") % d)
17631
0b241d7a8c62 templating: make new-style templating features work with command line lists
Matt Mackall <mpm@selenic.com>
parents: 17383
diff changeset
   519
31807
e6eb86b154c5 templater: provide loop counter as "index" keyword
Yuya Nishihara <yuya@tcha.org>
parents: 31806
diff changeset
   520
    for i, v in enumerate(diter):
28225
5c11702fe2a3 templater: fix list templating bug
Kostia Balytskyi <ikostia@fb.com>
parents: 28178
diff changeset
   521
        lm = mapping.copy()
31807
e6eb86b154c5 templater: provide loop counter as "index" keyword
Yuya Nishihara <yuya@tcha.org>
parents: 31806
diff changeset
   522
        lm['index'] = i
31806
8f203b491bb5 templater: rename variable "i" to "v" in runmap()
Yuya Nishihara <yuya@tcha.org>
parents: 31527
diff changeset
   523
        if isinstance(v, dict):
8f203b491bb5 templater: rename variable "i" to "v" in runmap()
Yuya Nishihara <yuya@tcha.org>
parents: 31527
diff changeset
   524
            lm.update(v)
17991
d605a82cf189 hgweb: display diff for a changeset against any parents (issue2810)
Weiwen <weiwen@fb.com>
parents: 17982
diff changeset
   525
            lm['originalnode'] = mapping.get('node')
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   526
            yield evalrawexp(context, lm, targ)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   527
        else:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   528
            # v is not an iterable of dicts, this happen when 'key'
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   529
            # has been fully expanded already and format is useless.
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   530
            # If so, return the expanded value.
31806
8f203b491bb5 templater: rename variable "i" to "v" in runmap()
Yuya Nishihara <yuya@tcha.org>
parents: 31527
diff changeset
   531
            yield v
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   532
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   533
def buildmember(exp, context):
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   534
    darg = compileexp(exp[1], context, methods)
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   535
    memb = getsymbol(exp[2])
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   536
    return (runmember, (darg, memb))
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   537
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   538
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
   539
    darg, memb = data
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   540
    d = evalrawexp(context, mapping, darg)
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   541
    if util.safehasattr(d, 'tomap'):
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   542
        lm = mapping.copy()
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   543
        lm.update(d.tomap())
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   544
        return runsymbol(context, lm, memb)
34536
4c1cfe54c08d templater: extend dot operator as a short for get(dict, key)
Yuya Nishihara <yuya@tcha.org>
parents: 34535
diff changeset
   545
    if util.safehasattr(d, 'get'):
4c1cfe54c08d templater: extend dot operator as a short for get(dict, key)
Yuya Nishihara <yuya@tcha.org>
parents: 34535
diff changeset
   546
        return _getdictitem(d, memb)
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   547
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   548
    sym = findsymbolicname(darg)
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   549
    if sym:
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   550
        raise error.ParseError(_("keyword '%s' has no member") % sym)
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   551
    else:
36574
ab7f86a748e6 py3: drop b'' from error message generated by templater.runmember()
Yuya Nishihara <yuya@tcha.org>
parents: 36573
diff changeset
   552
        raise error.ParseError(_("%r has no member") % pycompat.bytestr(d))
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   553
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   554
def buildnegate(exp, context):
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   555
    arg = compileexp(exp[1], context, exprmethods)
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   556
    return (runnegate, arg)
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   557
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   558
def runnegate(context, mapping, data):
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   559
    data = evalinteger(context, mapping, data,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   560
                       _('negation needs an integer argument'))
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   561
    return -data
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   562
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   563
def buildarithmetic(exp, context, func):
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   564
    left = compileexp(exp[1], context, exprmethods)
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   565
    right = compileexp(exp[2], context, exprmethods)
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   566
    return (runarithmetic, (func, left, right))
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   567
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   568
def runarithmetic(context, mapping, data):
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   569
    func, left, right = data
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   570
    left = evalinteger(context, mapping, left,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   571
                       _('arithmetic only defined on integers'))
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   572
    right = evalinteger(context, mapping, right,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   573
                        _('arithmetic only defined on integers'))
30116
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   574
    try:
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   575
        return func(left, right)
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   576
    except ZeroDivisionError:
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
   577
        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
   578
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   579
def buildfunc(exp, context):
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   580
    n = getsymbol(exp[1])
14925
ab545a15d807 templater: use a global funcs table
Matt Mackall <mpm@selenic.com>
parents: 14168
diff changeset
   581
    if n in funcs:
ab545a15d807 templater: use a global funcs table
Matt Mackall <mpm@selenic.com>
parents: 14168
diff changeset
   582
        f = funcs[n]
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   583
        args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
14925
ab545a15d807 templater: use a global funcs table
Matt Mackall <mpm@selenic.com>
parents: 14168
diff changeset
   584
        return (f, args)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   585
    if n in context._filters:
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   586
        args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   587
        if len(args) != 1:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   588
            raise error.ParseError(_("filter %s expects one argument") % n)
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   589
        f = context._filters[n]
26125
c990afab2243 templater: drop unneeded destructuring of argument tuple at buildfilter
Yuya Nishihara <yuya@tcha.org>
parents: 26124
diff changeset
   590
        return (runfilter, (args[0], f))
20857
6eb55310fcbc templater: raise error for unknown func
Sean Farley <sean.michael.farley@gmail.com>
parents: 20663
diff changeset
   591
    raise error.ParseError(_("unknown function '%s'") % n)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   592
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   593
def _buildfuncargs(exp, context, curmethods, funcname, argspec):
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   594
    """Compile parsed tree of function arguments into list or dict of
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   595
    (func, data) pairs
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   596
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   597
    >>> context = engine(lambda t: (runsymbol, t))
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   598
    >>> def fargs(expr, argspec):
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   599
    ...     x = _parseexpr(expr)
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   600
    ...     n = getsymbol(x[1])
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   601
    ...     return _buildfuncargs(x[2], context, exprmethods, n, argspec)
34154
be00af4a1ac5 doctest: coerce dict.keys() to list
Yuya Nishihara <yuya@tcha.org>
parents: 34152
diff changeset
   602
    >>> list(fargs(b'a(l=1, k=2)', b'k l m').keys())
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   603
    ['l', 'k']
34146
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34090
diff changeset
   604
    >>> args = fargs(b'a(opts=1, k=2)', b'**opts')
34154
be00af4a1ac5 doctest: coerce dict.keys() to list
Yuya Nishihara <yuya@tcha.org>
parents: 34152
diff changeset
   605
    >>> list(args.keys()), list(args[b'opts'].keys())
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   606
    (['opts'], ['opts', 'k'])
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   607
    """
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   608
    def compiledict(xs):
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   609
        return util.sortdict((k, compileexp(x, context, curmethods))
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   610
                             for k, x in xs.iteritems())
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   611
    def compilelist(xs):
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   612
        return [compileexp(x, context, curmethods) for x in xs]
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   613
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   614
    if not argspec:
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   615
        # filter or function with no argspec: return list of positional args
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   616
        return compilelist(getlist(exp))
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   617
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   618
    # function with argspec: return dict of named args
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   619
    _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec)
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   620
    treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   621
                                    keyvaluenode='keyvalue', keynode='symbol')
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   622
    compargs = util.sortdict()
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   623
    if varkey:
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   624
        compargs[varkey] = compilelist(treeargs.pop(varkey))
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   625
    if optkey:
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   626
        compargs[optkey] = compiledict(treeargs.pop(optkey))
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   627
    compargs.update(compiledict(treeargs))
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   628
    return compargs
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   629
31885
d18b624c1c06 templater: add parsing rule for key-value pair
Yuya Nishihara <yuya@tcha.org>
parents: 31884
diff changeset
   630
def buildkeyvaluepair(exp, content):
d18b624c1c06 templater: add parsing rule for key-value pair
Yuya Nishihara <yuya@tcha.org>
parents: 31884
diff changeset
   631
    raise error.ParseError(_("can't use a key-value pair in this context"))
d18b624c1c06 templater: add parsing rule for key-value pair
Yuya Nishihara <yuya@tcha.org>
parents: 31884
diff changeset
   632
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   633
# dict of template built-in functions
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   634
funcs = {}
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   635
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   636
templatefunc = registrar.templatefunc(funcs)
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   637
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   638
@templatefunc('date(date[, fmt])')
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   639
def date(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   640
    """Format a date. See :hg:`help dates` for formatting
26106
c568c4db036f templatefilters: remove redundant 'date' and 'strip' filters
Yuya Nishihara <yuya@tcha.org>
parents: 26105
diff changeset
   641
    strings. The default is a Unix date format, including the timezone:
c568c4db036f templatefilters: remove redundant 'date' and 'strip' filters
Yuya Nishihara <yuya@tcha.org>
parents: 26105
diff changeset
   642
    "Mon Sep 04 15:13:13 2006 0700"."""
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   643
    if not (1 <= len(args) <= 2):
23112
3226ed457928 i18n: add i18n comment to error messages of template functions
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22844
diff changeset
   644
        # i18n: "date" is a keyword
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   645
        raise error.ParseError(_("date expects one or two arguments"))
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   646
28334
9dc340f51e06 templater: make date() use helper function to evaluate argument
Yuya Nishihara <yuya@tcha.org>
parents: 28333
diff changeset
   647
    date = evalfuncarg(context, mapping, args[0])
24903
09124cce913f templater: fix crash by passing invalid object to date() function
Yuya Nishihara <yuya@tcha.org>
parents: 24886
diff changeset
   648
    fmt = None
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   649
    if len(args) == 2:
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   650
        fmt = evalstring(context, mapping, args[1])
24903
09124cce913f templater: fix crash by passing invalid object to date() function
Yuya Nishihara <yuya@tcha.org>
parents: 24886
diff changeset
   651
    try:
09124cce913f templater: fix crash by passing invalid object to date() function
Yuya Nishihara <yuya@tcha.org>
parents: 24886
diff changeset
   652
        if fmt is None:
36636
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36625
diff changeset
   653
            return dateutil.datestr(date)
24903
09124cce913f templater: fix crash by passing invalid object to date() function
Yuya Nishihara <yuya@tcha.org>
parents: 24886
diff changeset
   654
        else:
36636
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36625
diff changeset
   655
            return dateutil.datestr(date, fmt)
24903
09124cce913f templater: fix crash by passing invalid object to date() function
Yuya Nishihara <yuya@tcha.org>
parents: 24886
diff changeset
   656
    except (TypeError, ValueError):
09124cce913f templater: fix crash by passing invalid object to date() function
Yuya Nishihara <yuya@tcha.org>
parents: 24886
diff changeset
   657
        # i18n: "date" is a keyword
09124cce913f templater: fix crash by passing invalid object to date() function
Yuya Nishihara <yuya@tcha.org>
parents: 24886
diff changeset
   658
        raise error.ParseError(_("date expects a date information"))
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   659
31928
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   660
@templatefunc('dict([[key=]value...])', argspec='*args **kwargs')
31926
932241b8c644 templater: add dict() constructor
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   661
def dict_(context, mapping, args):
31928
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   662
    """Construct a dict from key-value pairs. A key may be omitted if
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   663
    a value expression can provide an unambiguous name."""
31926
932241b8c644 templater: add dict() constructor
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   664
    data = util.sortdict()
31928
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   665
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   666
    for v in args['args']:
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   667
        k = findsymbolicname(v)
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   668
        if not k:
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   669
            raise error.ParseError(_('dict key cannot be inferred'))
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   670
        if k in data or k in args['kwargs']:
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   671
            raise error.ParseError(_("duplicated dict key '%s' inferred") % k)
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   672
        data[k] = evalfuncarg(context, mapping, v)
277b3e2d711b templater: add shorthand for building a dict like {"key": key}
Yuya Nishihara <yuya@tcha.org>
parents: 31927
diff changeset
   673
31926
932241b8c644 templater: add dict() constructor
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   674
    data.update((k, evalfuncarg(context, mapping, v))
932241b8c644 templater: add dict() constructor
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   675
                for k, v in args['kwargs'].iteritems())
932241b8c644 templater: add dict() constructor
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   676
    return templatekw.hybriddict(data)
932241b8c644 templater: add dict() constructor
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   677
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   678
@templatefunc('diff([includepattern [, excludepattern]])')
22434
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   679
def diff(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   680
    """Show a diff, optionally
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
   681
    specifying files to include or exclude."""
22434
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   682
    if len(args) > 2:
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   683
        # i18n: "diff" is a keyword
27293
9e06e7fb037d grammar: favor zero, one, two over ... or no
timeless <timeless@mozdev.org>
parents: 26587
diff changeset
   684
        raise error.ParseError(_("diff expects zero, one, or two arguments"))
22434
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   685
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   686
    def getpatterns(i):
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   687
        if i < len(args):
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   688
            s = evalstring(context, mapping, args[i]).strip()
22434
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   689
            if s:
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   690
                return [s]
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   691
        return []
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   692
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
   693
    ctx = context.resource(mapping, 'ctx')
22434
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   694
    chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   695
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   696
    return ''.join(chunks)
40ce05b50148 templater: add "diff" template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22304
diff changeset
   697
34459
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   698
@templatefunc('extdata(source)', argspec='source')
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   699
def extdata(context, mapping, args):
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   700
    """Show a text read from the specified extdata source. (EXPERIMENTAL)"""
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   701
    if 'source' not in args:
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   702
        # i18n: "extdata" is a keyword
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   703
        raise error.ParseError(_('extdata expects one argument'))
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   704
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   705
    source = evalstring(context, mapping, args['source'])
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
   706
    cache = context.resource(mapping, 'cache').setdefault('extdata', {})
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
   707
    ctx = context.resource(mapping, 'ctx')
34459
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   708
    if source in cache:
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   709
        data = cache[source]
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   710
    else:
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   711
        data = cache[source] = scmutil.extdatasource(ctx.repo(), source)
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   712
    return data.get(ctx.rev(), '')
a1b89c8ad32d templater: add experimental support for extdata
Yuya Nishihara <yuya@tcha.org>
parents: 34353
diff changeset
   713
30012
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   714
@templatefunc('files(pattern)')
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   715
def files(context, mapping, args):
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   716
    """All files of the current changeset matching the pattern. See
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   717
    :hg:`help patterns`."""
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   718
    if not len(args) == 1:
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   719
        # i18n: "files" is a keyword
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   720
        raise error.ParseError(_("files expects one argument"))
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   721
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   722
    raw = evalstring(context, mapping, args[0])
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
   723
    ctx = context.resource(mapping, 'ctx')
30012
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   724
    m = ctx.match([raw])
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   725
    files = list(ctx.matches(m))
36620
121a20e5da56 templatekw: switch most of showlist template keywords to new API (issue5779)
Yuya Nishihara <yuya@tcha.org>
parents: 36579
diff changeset
   726
    return templatekw.compatlist(context, mapping, "file", files)
30012
e83f89d3b1f7 templates: add built-in files() function
Hannes Oldenburg <hannes.christian.oldenburg@gmail.com>
parents: 29858
diff changeset
   727
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   728
@templatefunc('fill(text[, width[, initialident[, hangindent]]])')
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   729
def fill(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   730
    """Fill many
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
   731
    paragraphs with optional indentation. See the "fill" filter."""
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   732
    if not (1 <= len(args) <= 4):
23112
3226ed457928 i18n: add i18n comment to error messages of template functions
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22844
diff changeset
   733
        # i18n: "fill" is a keyword
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   734
        raise error.ParseError(_("fill expects one to four arguments"))
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   735
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   736
    text = evalstring(context, mapping, args[0])
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   737
    width = 76
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   738
    initindent = ''
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   739
    hangindent = ''
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   740
    if 2 <= len(args) <= 4:
28343
a6c2310b3827 templater: factor out function that evaluates argument as integer
Yuya Nishihara <yuya@tcha.org>
parents: 28334
diff changeset
   741
        width = evalinteger(context, mapping, args[1],
a6c2310b3827 templater: factor out function that evaluates argument as integer
Yuya Nishihara <yuya@tcha.org>
parents: 28334
diff changeset
   742
                            # i18n: "fill" is a keyword
a6c2310b3827 templater: factor out function that evaluates argument as integer
Yuya Nishihara <yuya@tcha.org>
parents: 28334
diff changeset
   743
                            _("fill expects an integer width"))
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   744
        try:
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   745
            initindent = evalstring(context, mapping, args[2])
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   746
            hangindent = evalstring(context, mapping, args[3])
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   747
        except IndexError:
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   748
            pass
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   749
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   750
    return templatefilters.fill(text, width, initindent, hangindent)
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   751
31179
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   752
@templatefunc('formatnode(node)')
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   753
def formatnode(context, mapping, args):
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   754
    """Obtain the preferred form of a changeset hash. (DEPRECATED)"""
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   755
    if len(args) != 1:
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   756
        # i18n: "formatnode" is a keyword
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   757
        raise error.ParseError(_("formatnode expects one argument"))
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   758
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
   759
    ui = context.resource(mapping, 'ui')
31179
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   760
    node = evalstring(context, mapping, args[0])
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   761
    if ui.debugflag:
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   762
        return node
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   763
    return templatefilters.short(node)
48a8b2e5fe31 templater: port formatnode filter from changeset_templater
Yuya Nishihara <yuya@tcha.org>
parents: 31044
diff changeset
   764
31887
f7b3677f66cd templater: port pad() to take keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31886
diff changeset
   765
@templatefunc('pad(text, width[, fillchar=\' \'[, left=False]])',
f7b3677f66cd templater: port pad() to take keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31886
diff changeset
   766
              argspec='text width fillchar left')
20370
aa51392da507 template: add pad function for padding output
Durham Goode <durham@fb.com>
parents: 20369
diff changeset
   767
def pad(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   768
    """Pad text with a
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
   769
    fill character."""
31887
f7b3677f66cd templater: port pad() to take keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31886
diff changeset
   770
    if 'text' not in args or 'width' not in args:
23112
3226ed457928 i18n: add i18n comment to error messages of template functions
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22844
diff changeset
   771
        # i18n: "pad" is a keyword
20370
aa51392da507 template: add pad function for padding output
Durham Goode <durham@fb.com>
parents: 20369
diff changeset
   772
        raise error.ParseError(_("pad() expects two to four arguments"))
aa51392da507 template: add pad function for padding output
Durham Goode <durham@fb.com>
parents: 20369
diff changeset
   773
31887
f7b3677f66cd templater: port pad() to take keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31886
diff changeset
   774
    width = evalinteger(context, mapping, args['width'],
28345
d81437c91a26 templater: fix pad() to evaluate int argument and handle error
Yuya Nishihara <yuya@tcha.org>
parents: 28344
diff changeset
   775
                        # i18n: "pad" is a keyword
d81437c91a26 templater: fix pad() to evaluate int argument and handle error
Yuya Nishihara <yuya@tcha.org>
parents: 28344
diff changeset
   776
                        _("pad() expects an integer width"))
20370
aa51392da507 template: add pad function for padding output
Durham Goode <durham@fb.com>
parents: 20369
diff changeset
   777
31887
f7b3677f66cd templater: port pad() to take keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31886
diff changeset
   778
    text = evalstring(context, mapping, args['text'])
20370
aa51392da507 template: add pad function for padding output
Durham Goode <durham@fb.com>
parents: 20369
diff changeset
   779
29829
407879b0893b templater: rename "right" argument of pad() function
Yuya Nishihara <yuya@tcha.org>
parents: 29828
diff changeset
   780
    left = False
20370
aa51392da507 template: add pad function for padding output
Durham Goode <durham@fb.com>
parents: 20369
diff changeset
   781
    fillchar = ' '
31887
f7b3677f66cd templater: port pad() to take keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31886
diff changeset
   782
    if 'fillchar' in args:
f7b3677f66cd templater: port pad() to take keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31886
diff changeset
   783
        fillchar = evalstring(context, mapping, args['fillchar'])
31527
44c591f63458 templater: make pad() strip color codes before computing width (issue5416)
Yuya Nishihara <yuya@tcha.org>
parents: 31526
diff changeset
   784
        if len(color.stripeffects(fillchar)) != 1:
31525
3725986b151a templater: reject bad fillchar argument passed to pad()
Yuya Nishihara <yuya@tcha.org>
parents: 31179
diff changeset
   785
            # i18n: "pad" is a keyword
3725986b151a templater: reject bad fillchar argument passed to pad()
Yuya Nishihara <yuya@tcha.org>
parents: 31179
diff changeset
   786
            raise error.ParseError(_("pad() expects a single fill character"))
31887
f7b3677f66cd templater: port pad() to take keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31886
diff changeset
   787
    if 'left' in args:
f7b3677f66cd templater: port pad() to take keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31886
diff changeset
   788
        left = evalboolean(context, mapping, args['left'])
20370
aa51392da507 template: add pad function for padding output
Durham Goode <durham@fb.com>
parents: 20369
diff changeset
   789
31527
44c591f63458 templater: make pad() strip color codes before computing width (issue5416)
Yuya Nishihara <yuya@tcha.org>
parents: 31526
diff changeset
   790
    fillwidth = width - encoding.colwidth(color.stripeffects(text))
31526
6f150bb19317 templater: make pad() compute actual width
Yuya Nishihara <yuya@tcha.org>
parents: 31525
diff changeset
   791
    if fillwidth <= 0:
6f150bb19317 templater: make pad() compute actual width
Yuya Nishihara <yuya@tcha.org>
parents: 31525
diff changeset
   792
        return text
29829
407879b0893b templater: rename "right" argument of pad() function
Yuya Nishihara <yuya@tcha.org>
parents: 29828
diff changeset
   793
    if left:
31526
6f150bb19317 templater: make pad() compute actual width
Yuya Nishihara <yuya@tcha.org>
parents: 31525
diff changeset
   794
        return fillchar * fillwidth + text
20370
aa51392da507 template: add pad function for padding output
Durham Goode <durham@fb.com>
parents: 20369
diff changeset
   795
    else:
31526
6f150bb19317 templater: make pad() compute actual width
Yuya Nishihara <yuya@tcha.org>
parents: 31525
diff changeset
   796
        return text + fillchar * fillwidth
20370
aa51392da507 template: add pad function for padding output
Durham Goode <durham@fb.com>
parents: 20369
diff changeset
   797
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   798
@templatefunc('indent(text, indentchars[, firstline])')
25489
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   799
def indent(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   800
    """Indents all non-empty lines
25489
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   801
    with the characters given in the indentchars string. An optional
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   802
    third parameter will override the indent for the first line only
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   803
    if present."""
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   804
    if not (2 <= len(args) <= 3):
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   805
        # i18n: "indent" is a keyword
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   806
        raise error.ParseError(_("indent() expects two or three arguments"))
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   807
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   808
    text = evalstring(context, mapping, args[0])
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   809
    indent = evalstring(context, mapping, args[1])
25489
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   810
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   811
    if len(args) == 3:
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   812
        firstline = evalstring(context, mapping, args[2])
25489
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   813
    else:
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   814
        firstline = indent
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   815
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   816
    # the indent function doesn't indent the first line, so we do it here
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   817
    return templatefilters.indent(firstline + text, indent)
ef8956aa8755 templater: introduce indent function
Ryan McElroy <rmcelroy@fb.com>
parents: 25096
diff changeset
   818
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   819
@templatefunc('get(dict, key)')
18582
ef78450c8df6 templater: add get() function to access dict element (e.g. extra)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 18289
diff changeset
   820
def get(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   821
    """Get an attribute/key from an object. Some keywords
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
   822
    are complex types. This function allows you to obtain the value of an
26197
fb6c08a9b40a templater: fix get English
timeless@mozdev.org
parents: 26188
diff changeset
   823
    attribute on these types."""
18582
ef78450c8df6 templater: add get() function to access dict element (e.g. extra)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 18289
diff changeset
   824
    if len(args) != 2:
ef78450c8df6 templater: add get() function to access dict element (e.g. extra)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 18289
diff changeset
   825
        # i18n: "get" is a keyword
ef78450c8df6 templater: add get() function to access dict element (e.g. extra)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 18289
diff changeset
   826
        raise error.ParseError(_("get() expects two arguments"))
ef78450c8df6 templater: add get() function to access dict element (e.g. extra)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 18289
diff changeset
   827
28331
2874db5462d3 templater: fix get() to evaluate arguments eagerly
Yuya Nishihara <yuya@tcha.org>
parents: 28225
diff changeset
   828
    dictarg = evalfuncarg(context, mapping, args[0])
18582
ef78450c8df6 templater: add get() function to access dict element (e.g. extra)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 18289
diff changeset
   829
    if not util.safehasattr(dictarg, 'get'):
ef78450c8df6 templater: add get() function to access dict element (e.g. extra)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 18289
diff changeset
   830
        # i18n: "get" is a keyword
ef78450c8df6 templater: add get() function to access dict element (e.g. extra)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 18289
diff changeset
   831
        raise error.ParseError(_("get() expects a dict as first argument"))
ef78450c8df6 templater: add get() function to access dict element (e.g. extra)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 18289
diff changeset
   832
28331
2874db5462d3 templater: fix get() to evaluate arguments eagerly
Yuya Nishihara <yuya@tcha.org>
parents: 28225
diff changeset
   833
    key = evalfuncarg(context, mapping, args[1])
34536
4c1cfe54c08d templater: extend dot operator as a short for get(dict, key)
Yuya Nishihara <yuya@tcha.org>
parents: 34535
diff changeset
   834
    return _getdictitem(dictarg, key)
4c1cfe54c08d templater: extend dot operator as a short for get(dict, key)
Yuya Nishihara <yuya@tcha.org>
parents: 34535
diff changeset
   835
4c1cfe54c08d templater: extend dot operator as a short for get(dict, key)
Yuya Nishihara <yuya@tcha.org>
parents: 34535
diff changeset
   836
def _getdictitem(dictarg, key):
34534
b3073e175c17 templater: wrap get/min/max result so map operation can apply to element
Yuya Nishihara <yuya@tcha.org>
parents: 34459
diff changeset
   837
    val = dictarg.get(key)
b3073e175c17 templater: wrap get/min/max result so map operation can apply to element
Yuya Nishihara <yuya@tcha.org>
parents: 34459
diff changeset
   838
    if val is None:
b3073e175c17 templater: wrap get/min/max result so map operation can apply to element
Yuya Nishihara <yuya@tcha.org>
parents: 34459
diff changeset
   839
        return
b3073e175c17 templater: wrap get/min/max result so map operation can apply to element
Yuya Nishihara <yuya@tcha.org>
parents: 34459
diff changeset
   840
    return templatekw.wraphybridvalue(dictarg, key, val)
18582
ef78450c8df6 templater: add get() function to access dict element (e.g. extra)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 18289
diff changeset
   841
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   842
@templatefunc('if(expr, then[, else])')
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   843
def if_(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   844
    """Conditionally execute based on the result of
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
   845
    an expression."""
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   846
    if not (2 <= len(args) <= 3):
17890
ca6850b9dd9e i18n: add "i18n" comment to error messages of template functions
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17729
diff changeset
   847
        # i18n: "if" is a keyword
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   848
        raise error.ParseError(_("if expects two or three arguments"))
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   849
29827
034412ca28c3 templater: fix if() to not evaluate False as bool('False')
Yuya Nishihara <yuya@tcha.org>
parents: 29826
diff changeset
   850
    test = evalboolean(context, mapping, args[0])
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   851
    if test:
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   852
        yield evalrawexp(context, mapping, args[1])
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   853
    elif len(args) == 3:
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   854
        yield evalrawexp(context, mapping, args[2])
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   855
30049
f18cc848b48e templater: use "needle" and "haystack" as (meta-)variables for ifcontains()
Anton Shestakov <av6@dwimlabs.net>
parents: 30012
diff changeset
   856
@templatefunc('ifcontains(needle, haystack, then[, else])')
20518
1e43f15a647f template: add ifcontains template function
Durham Goode <durham@fb.com>
parents: 20371
diff changeset
   857
def ifcontains(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   858
    """Conditionally execute based
30049
f18cc848b48e templater: use "needle" and "haystack" as (meta-)variables for ifcontains()
Anton Shestakov <av6@dwimlabs.net>
parents: 30012
diff changeset
   859
    on whether the item "needle" is in "haystack"."""
20518
1e43f15a647f template: add ifcontains template function
Durham Goode <durham@fb.com>
parents: 20371
diff changeset
   860
    if not (3 <= len(args) <= 4):
1e43f15a647f template: add ifcontains template function
Durham Goode <durham@fb.com>
parents: 20371
diff changeset
   861
        # i18n: "ifcontains" is a keyword
1e43f15a647f template: add ifcontains template function
Durham Goode <durham@fb.com>
parents: 20371
diff changeset
   862
        raise error.ParseError(_("ifcontains expects three or four arguments"))
1e43f15a647f template: add ifcontains template function
Durham Goode <durham@fb.com>
parents: 20371
diff changeset
   863
30049
f18cc848b48e templater: use "needle" and "haystack" as (meta-)variables for ifcontains()
Anton Shestakov <av6@dwimlabs.net>
parents: 30012
diff changeset
   864
    haystack = evalfuncarg(context, mapping, args[1])
34659
3edfd472f3cb templater: fix ifcontains() to handle type mismatch gracefully
Yuya Nishihara <yuya@tcha.org>
parents: 34581
diff changeset
   865
    try:
3edfd472f3cb templater: fix ifcontains() to handle type mismatch gracefully
Yuya Nishihara <yuya@tcha.org>
parents: 34581
diff changeset
   866
        needle = evalastype(context, mapping, args[0],
3edfd472f3cb templater: fix ifcontains() to handle type mismatch gracefully
Yuya Nishihara <yuya@tcha.org>
parents: 34581
diff changeset
   867
                            getattr(haystack, 'keytype', None) or bytes)
3edfd472f3cb templater: fix ifcontains() to handle type mismatch gracefully
Yuya Nishihara <yuya@tcha.org>
parents: 34581
diff changeset
   868
        found = (needle in haystack)
3edfd472f3cb templater: fix ifcontains() to handle type mismatch gracefully
Yuya Nishihara <yuya@tcha.org>
parents: 34581
diff changeset
   869
    except error.ParseError:
3edfd472f3cb templater: fix ifcontains() to handle type mismatch gracefully
Yuya Nishihara <yuya@tcha.org>
parents: 34581
diff changeset
   870
        found = False
20518
1e43f15a647f template: add ifcontains template function
Durham Goode <durham@fb.com>
parents: 20371
diff changeset
   871
34659
3edfd472f3cb templater: fix ifcontains() to handle type mismatch gracefully
Yuya Nishihara <yuya@tcha.org>
parents: 34581
diff changeset
   872
    if found:
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   873
        yield evalrawexp(context, mapping, args[2])
20518
1e43f15a647f template: add ifcontains template function
Durham Goode <durham@fb.com>
parents: 20371
diff changeset
   874
    elif len(args) == 4:
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   875
        yield evalrawexp(context, mapping, args[3])
20518
1e43f15a647f template: add ifcontains template function
Durham Goode <durham@fb.com>
parents: 20371
diff changeset
   876
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   877
@templatefunc('ifeq(expr1, expr2, then[, else])')
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   878
def ifeq(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   879
    """Conditionally execute based on
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
   880
    whether 2 items are equivalent."""
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   881
    if not (3 <= len(args) <= 4):
17890
ca6850b9dd9e i18n: add "i18n" comment to error messages of template functions
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 17729
diff changeset
   882
        # i18n: "ifeq" is a keyword
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   883
        raise error.ParseError(_("ifeq expects three or four arguments"))
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   884
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   885
    test = evalstring(context, mapping, args[0])
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   886
    match = evalstring(context, mapping, args[1])
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   887
    if test == match:
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   888
        yield evalrawexp(context, mapping, args[2])
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   889
    elif len(args) == 4:
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   890
        yield evalrawexp(context, mapping, args[3])
17636
ce18dbcd91c8 templater: add if/ifeq conditionals
Matt Mackall <mpm@selenic.com>
parents: 17635
diff changeset
   891
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   892
@templatefunc('join(list, sep)')
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   893
def join(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   894
    """Join items in a list with a delimiter."""
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   895
    if not (1 <= len(args) <= 2):
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   896
        # i18n: "join" is a keyword
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   897
        raise error.ParseError(_("join expects one or two arguments"))
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   898
34333
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   899
    # TODO: perhaps this should be evalfuncarg(), but it can't because hgweb
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   900
    # abuses generator as a keyword that returns a list of dicts.
e60c601953d7 templater: extract helper to just evaluate template expression
Yuya Nishihara <yuya@tcha.org>
parents: 34332
diff changeset
   901
    joinset = evalrawexp(context, mapping, args[0])
34337
89aec1834a86 templatekw: add new-style template expansion to {manifest}
Yuya Nishihara <yuya@tcha.org>
parents: 34336
diff changeset
   902
    joinset = templatekw.unwrapvalue(joinset)
34335
dd28b1f55eb8 templatekw: just pass underlying value (or key) to joinfmt() function
Yuya Nishihara <yuya@tcha.org>
parents: 34333
diff changeset
   903
    joinfmt = getattr(joinset, 'joinfmt', pycompat.identity)
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   904
    joiner = " "
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   905
    if len(args) > 1:
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   906
        joiner = evalstring(context, mapping, args[1])
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   907
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   908
    first = True
36573
a16fceb686a7 py3: fix join(), min(), and max() template functions over string
Yuya Nishihara <yuya@tcha.org>
parents: 36539
diff changeset
   909
    for x in pycompat.maybebytestr(joinset):
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   910
        if first:
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   911
            first = False
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   912
        else:
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   913
            yield joiner
34335
dd28b1f55eb8 templatekw: just pass underlying value (or key) to joinfmt() function
Yuya Nishihara <yuya@tcha.org>
parents: 34333
diff changeset
   914
        yield joinfmt(x)
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
   915
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   916
@templatefunc('label(label, expr)')
18289
9bfb53106328 templater: add no-op template function 'label'
Sean Farley <sean.michael.farley@gmail.com>
parents: 17991
diff changeset
   917
def label(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   918
    """Apply a label to generated content. Content with
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
   919
    a label applied can result in additional post-processing, such as
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
   920
    automatic colorization."""
18289
9bfb53106328 templater: add no-op template function 'label'
Sean Farley <sean.michael.farley@gmail.com>
parents: 17991
diff changeset
   921
    if len(args) != 2:
9bfb53106328 templater: add no-op template function 'label'
Sean Farley <sean.michael.farley@gmail.com>
parents: 17991
diff changeset
   922
        # i18n: "label" is a keyword
9bfb53106328 templater: add no-op template function 'label'
Sean Farley <sean.michael.farley@gmail.com>
parents: 17991
diff changeset
   923
        raise error.ParseError(_("label expects two arguments"))
9bfb53106328 templater: add no-op template function 'label'
Sean Farley <sean.michael.farley@gmail.com>
parents: 17991
diff changeset
   924
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
   925
    ui = context.resource(mapping, 'ui')
28374
af3bd9d1dbc1 templater: move label() function from color extension
Yuya Nishihara <yuya@tcha.org>
parents: 28373
diff changeset
   926
    thing = evalstring(context, mapping, args[1])
af3bd9d1dbc1 templater: move label() function from color extension
Yuya Nishihara <yuya@tcha.org>
parents: 28373
diff changeset
   927
    # preserve unknown symbol as literal so effects like 'red', 'bold',
af3bd9d1dbc1 templater: move label() function from color extension
Yuya Nishihara <yuya@tcha.org>
parents: 28373
diff changeset
   928
    # etc. don't need to be quoted
af3bd9d1dbc1 templater: move label() function from color extension
Yuya Nishihara <yuya@tcha.org>
parents: 28373
diff changeset
   929
    label = evalstringliteral(context, mapping, args[0])
af3bd9d1dbc1 templater: move label() function from color extension
Yuya Nishihara <yuya@tcha.org>
parents: 28373
diff changeset
   930
28384
3356bf61fa25 formatter: make labels work with templated output
Kostia Balytskyi <ikostia@fb.com>
parents: 28374
diff changeset
   931
    return ui.label(thing, label)
18289
9bfb53106328 templater: add no-op template function 'label'
Sean Farley <sean.michael.farley@gmail.com>
parents: 17991
diff changeset
   932
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   933
@templatefunc('latesttag([pattern])')
26485
43bf9471fae9 templater: introduce {latesttag()} function to match a pattern (issue4184)
Matt Harbison <matt_harbison@yahoo.com>
parents: 26334
diff changeset
   934
def latesttag(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   935
    """The global tags matching the given pattern on the
31850
f0d719e513fc templatekw: clarify the result of {latesttag} when no tag exists
Matt Harbison <matt_harbison@yahoo.com>
parents: 31807
diff changeset
   936
    most recent globally tagged ancestor of this changeset.
f0d719e513fc templatekw: clarify the result of {latesttag} when no tag exists
Matt Harbison <matt_harbison@yahoo.com>
parents: 31807
diff changeset
   937
    If no such tags exist, the "{tag}" template resolves to
f0d719e513fc templatekw: clarify the result of {latesttag} when no tag exists
Matt Harbison <matt_harbison@yahoo.com>
parents: 31807
diff changeset
   938
    the string "null"."""
26485
43bf9471fae9 templater: introduce {latesttag()} function to match a pattern (issue4184)
Matt Harbison <matt_harbison@yahoo.com>
parents: 26334
diff changeset
   939
    if len(args) > 1:
43bf9471fae9 templater: introduce {latesttag()} function to match a pattern (issue4184)
Matt Harbison <matt_harbison@yahoo.com>
parents: 26334
diff changeset
   940
        # i18n: "latesttag" is a keyword
43bf9471fae9 templater: introduce {latesttag()} function to match a pattern (issue4184)
Matt Harbison <matt_harbison@yahoo.com>
parents: 26334
diff changeset
   941
        raise error.ParseError(_("latesttag expects at most one argument"))
43bf9471fae9 templater: introduce {latesttag()} function to match a pattern (issue4184)
Matt Harbison <matt_harbison@yahoo.com>
parents: 26334
diff changeset
   942
43bf9471fae9 templater: introduce {latesttag()} function to match a pattern (issue4184)
Matt Harbison <matt_harbison@yahoo.com>
parents: 26334
diff changeset
   943
    pattern = None
43bf9471fae9 templater: introduce {latesttag()} function to match a pattern (issue4184)
Matt Harbison <matt_harbison@yahoo.com>
parents: 26334
diff changeset
   944
    if len(args) == 1:
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
   945
        pattern = evalstring(context, mapping, args[0])
36625
b5d39a09656a templatekw: switch latesttags template keywords to new API
Yuya Nishihara <yuya@tcha.org>
parents: 36624
diff changeset
   946
    return templatekw.showlatesttags(context, mapping, pattern)
26485
43bf9471fae9 templater: introduce {latesttag()} function to match a pattern (issue4184)
Matt Harbison <matt_harbison@yahoo.com>
parents: 26334
diff changeset
   947
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   948
@templatefunc('localdate(date[, tz])')
26127
7012be5ab5bd templater: port localdate filter to a function
Yuya Nishihara <yuya@tcha.org>
parents: 26125
diff changeset
   949
def localdate(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
   950
    """Converts a date to the specified timezone.
26128
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   951
    The default is local date."""
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   952
    if not (1 <= len(args) <= 2):
26127
7012be5ab5bd templater: port localdate filter to a function
Yuya Nishihara <yuya@tcha.org>
parents: 26125
diff changeset
   953
        # i18n: "localdate" is a keyword
26128
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   954
        raise error.ParseError(_("localdate expects one or two arguments"))
26127
7012be5ab5bd templater: port localdate filter to a function
Yuya Nishihara <yuya@tcha.org>
parents: 26125
diff changeset
   955
7012be5ab5bd templater: port localdate filter to a function
Yuya Nishihara <yuya@tcha.org>
parents: 26125
diff changeset
   956
    date = evalfuncarg(context, mapping, args[0])
7012be5ab5bd templater: port localdate filter to a function
Yuya Nishihara <yuya@tcha.org>
parents: 26125
diff changeset
   957
    try:
36636
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36625
diff changeset
   958
        date = dateutil.parsedate(date)
26127
7012be5ab5bd templater: port localdate filter to a function
Yuya Nishihara <yuya@tcha.org>
parents: 26125
diff changeset
   959
    except AttributeError:  # not str nor date tuple
7012be5ab5bd templater: port localdate filter to a function
Yuya Nishihara <yuya@tcha.org>
parents: 26125
diff changeset
   960
        # i18n: "localdate" is a keyword
7012be5ab5bd templater: port localdate filter to a function
Yuya Nishihara <yuya@tcha.org>
parents: 26125
diff changeset
   961
        raise error.ParseError(_("localdate expects a date information"))
26128
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   962
    if len(args) >= 2:
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   963
        tzoffset = None
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   964
        tz = evalfuncarg(context, mapping, args[1])
36579
7f6be7121b28 py3: replace type 'str' by 'bytes' in templater.py
Yuya Nishihara <yuya@tcha.org>
parents: 36575
diff changeset
   965
        if isinstance(tz, bytes):
36636
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36625
diff changeset
   966
            tzoffset, remainder = dateutil.parsetimezone(tz)
29636
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29085
diff changeset
   967
            if remainder:
84ef4517de03 date: refactor timezone parsing
Matt Mackall <mpm@selenic.com>
parents: 29085
diff changeset
   968
                tzoffset = None
26128
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   969
        if tzoffset is None:
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   970
            try:
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   971
                tzoffset = int(tz)
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   972
            except (TypeError, ValueError):
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   973
                # i18n: "localdate" is a keyword
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   974
                raise error.ParseError(_("localdate expects a timezone"))
51f6940d3b4f templater: add optional timezone argument to localdate()
Yuya Nishihara <yuya@tcha.org>
parents: 26127
diff changeset
   975
    else:
36636
c6061cadb400 util: extract all date-related utils in utils/dateutil module
Boris Feld <boris.feld@octobus.net>
parents: 36625
diff changeset
   976
        tzoffset = dateutil.makedate()[1]
26127
7012be5ab5bd templater: port localdate filter to a function
Yuya Nishihara <yuya@tcha.org>
parents: 26125
diff changeset
   977
    return (date[0], tzoffset)
7012be5ab5bd templater: port localdate filter to a function
Yuya Nishihara <yuya@tcha.org>
parents: 26125
diff changeset
   978
34013
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   979
@templatefunc('max(iterable)')
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   980
def max_(context, mapping, args, **kwargs):
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   981
    """Return the max of an iterable"""
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   982
    if len(args) != 1:
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   983
        # i18n: "max" is a keyword
35003
fdd09d87635b templater: fix "one arguments"
Anton Shestakov <av6@dwimlabs.net>
parents: 34838
diff changeset
   984
        raise error.ParseError(_("max expects one argument"))
34013
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   985
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   986
    iterable = evalfuncarg(context, mapping, args[0])
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   987
    try:
36573
a16fceb686a7 py3: fix join(), min(), and max() template functions over string
Yuya Nishihara <yuya@tcha.org>
parents: 36539
diff changeset
   988
        x = max(pycompat.maybebytestr(iterable))
34013
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   989
    except (TypeError, ValueError):
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   990
        # i18n: "max" is a keyword
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   991
        raise error.ParseError(_("max first argument should be an iterable"))
34534
b3073e175c17 templater: wrap get/min/max result so map operation can apply to element
Yuya Nishihara <yuya@tcha.org>
parents: 34459
diff changeset
   992
    return templatekw.wraphybridvalue(iterable, x, x)
34013
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   993
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   994
@templatefunc('min(iterable)')
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   995
def min_(context, mapping, args, **kwargs):
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   996
    """Return the min of an iterable"""
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   997
    if len(args) != 1:
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
   998
        # i18n: "min" is a keyword
35003
fdd09d87635b templater: fix "one arguments"
Anton Shestakov <av6@dwimlabs.net>
parents: 34838
diff changeset
   999
        raise error.ParseError(_("min expects one argument"))
34013
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1000
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1001
    iterable = evalfuncarg(context, mapping, args[0])
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1002
    try:
36573
a16fceb686a7 py3: fix join(), min(), and max() template functions over string
Yuya Nishihara <yuya@tcha.org>
parents: 36539
diff changeset
  1003
        x = min(pycompat.maybebytestr(iterable))
34013
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1004
    except (TypeError, ValueError):
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1005
        # i18n: "min" is a keyword
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1006
        raise error.ParseError(_("min first argument should be an iterable"))
34534
b3073e175c17 templater: wrap get/min/max result so map operation can apply to element
Yuya Nishihara <yuya@tcha.org>
parents: 34459
diff changeset
  1007
    return templatekw.wraphybridvalue(iterable, x, x)
34013
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1008
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1009
@templatefunc('mod(a, b)')
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1010
def mod(context, mapping, args):
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1011
    """Calculate a mod b such that a / b + a mod b == a"""
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1012
    if not len(args) == 2:
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1013
        # i18n: "mod" is a keyword
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1014
        raise error.ParseError(_("mod expects two arguments"))
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1015
30116
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
  1016
    func = lambda a, b: a % b
1c01fa29630f templater: handle division by zero in arithmetic
Simon Farnsworth <simonfar@fb.com>
parents: 30115
diff changeset
  1017
    return runarithmetic(context, mapping, (func, args[0], args[1]))
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1018
34294
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1019
@templatefunc('obsfateoperations(markers)')
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1020
def obsfateoperations(context, mapping, args):
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1021
    """Compute obsfate related information based on markers (EXPERIMENTAL)"""
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1022
    if len(args) != 1:
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1023
        # i18n: "obsfateoperations" is a keyword
35003
fdd09d87635b templater: fix "one arguments"
Anton Shestakov <av6@dwimlabs.net>
parents: 34838
diff changeset
  1024
        raise error.ParseError(_("obsfateoperations expects one argument"))
34294
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1025
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1026
    markers = evalfuncarg(context, mapping, args[0])
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1027
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1028
    try:
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1029
        data = obsutil.markersoperations(markers)
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1030
        return templatekw.hybridlist(data, name='operation')
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1031
    except (TypeError, KeyError):
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1032
        # i18n: "obsfateoperations" is a keyword
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1033
        errmsg = _("obsfateoperations first argument should be an iterable")
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1034
        raise error.ParseError(errmsg)
7cdc8c5a481a templates: introduce a obsfateoperation() function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34257
diff changeset
  1035
34013
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1036
@templatefunc('obsfatedate(markers)')
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1037
def obsfatedate(context, mapping, args):
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1038
    """Compute obsfate related information based on markers (EXPERIMENTAL)"""
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1039
    if len(args) != 1:
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1040
        # i18n: "obsfatedate" is a keyword
35003
fdd09d87635b templater: fix "one arguments"
Anton Shestakov <av6@dwimlabs.net>
parents: 34838
diff changeset
  1041
        raise error.ParseError(_("obsfatedate expects one argument"))
34013
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1042
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1043
    markers = evalfuncarg(context, mapping, args[0])
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1044
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1045
    try:
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1046
        data = obsutil.markersdates(markers)
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1047
        return templatekw.hybridlist(data, name='date', fmt='%d %d')
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1048
    except (TypeError, KeyError):
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1049
        # i18n: "obsfatedate" is a keyword
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1050
        errmsg = _("obsfatedate first argument should be an iterable")
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1051
        raise error.ParseError(errmsg)
c35c0f54f420 template: compute dates in obsfatedate
Boris Feld <boris.feld@octobus.net>
parents: 34012
diff changeset
  1052
34012
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1053
@templatefunc('obsfateusers(markers)')
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1054
def obsfateusers(context, mapping, args):
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1055
    """Compute obsfate related information based on markers (EXPERIMENTAL)"""
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1056
    if len(args) != 1:
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1057
        # i18n: "obsfateusers" is a keyword
35003
fdd09d87635b templater: fix "one arguments"
Anton Shestakov <av6@dwimlabs.net>
parents: 34838
diff changeset
  1058
        raise error.ParseError(_("obsfateusers expects one argument"))
34012
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1059
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1060
    markers = evalfuncarg(context, mapping, args[0])
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1061
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1062
    try:
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1063
        data = obsutil.markersusers(markers)
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1064
        return templatekw.hybridlist(data, name='user')
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1065
    except (TypeError, KeyError, ValueError):
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1066
        # i18n: "obsfateusers" is a keyword
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1067
        msg = _("obsfateusers first argument should be an iterable of "
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1068
                "obsmakers")
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1069
        raise error.ParseError(msg)
38f08eaba6b0 template: compute user in obsfateusers
Boris Feld <boris.feld@octobus.net>
parents: 34011
diff changeset
  1070
35049
b81ad5b78a81 obsfate: makes successorsetverb takes the markers as argument
Boris Feld <boris.feld@octobus.net>
parents: 34838
diff changeset
  1071
@templatefunc('obsfateverb(successors, markers)')
34011
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1072
def obsfateverb(context, mapping, args):
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1073
    """Compute obsfate related information based on successors (EXPERIMENTAL)"""
35049
b81ad5b78a81 obsfate: makes successorsetverb takes the markers as argument
Boris Feld <boris.feld@octobus.net>
parents: 34838
diff changeset
  1074
    if len(args) != 2:
34011
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1075
        # i18n: "obsfateverb" is a keyword
35049
b81ad5b78a81 obsfate: makes successorsetverb takes the markers as argument
Boris Feld <boris.feld@octobus.net>
parents: 34838
diff changeset
  1076
        raise error.ParseError(_("obsfateverb expects two arguments"))
34011
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1077
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1078
    successors = evalfuncarg(context, mapping, args[0])
35049
b81ad5b78a81 obsfate: makes successorsetverb takes the markers as argument
Boris Feld <boris.feld@octobus.net>
parents: 34838
diff changeset
  1079
    markers = evalfuncarg(context, mapping, args[1])
34011
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1080
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1081
    try:
35049
b81ad5b78a81 obsfate: makes successorsetverb takes the markers as argument
Boris Feld <boris.feld@octobus.net>
parents: 34838
diff changeset
  1082
        return obsutil.obsfateverb(successors, markers)
34011
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1083
    except TypeError:
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1084
        # i18n: "obsfateverb" is a keyword
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1085
        errmsg = _("obsfateverb first argument should be countable")
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1086
        raise error.ParseError(errmsg)
3d0f8918351b template: compute verb in obsfateverb
Boris Feld <boris.feld@octobus.net>
parents: 33554
diff changeset
  1087
30083
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1088
@templatefunc('relpath(path)')
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1089
def relpath(context, mapping, args):
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1090
    """Convert a repository-absolute path into a filesystem path relative to
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1091
    the current working directory."""
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1092
    if len(args) != 1:
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1093
        # i18n: "relpath" is a keyword
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1094
        raise error.ParseError(_("relpath expects one argument"))
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1095
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1096
    repo = context.resource(mapping, 'ctx').repo()
30083
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1097
    path = evalstring(context, mapping, args[0])
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1098
    return repo.pathto(path)
bd1f043d1ea3 templater: add relpath() to convert repo path to relative path (issue5394)
Yuya Nishihara <yuya@tcha.org>
parents: 30049
diff changeset
  1099
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1100
@templatefunc('revset(query[, formatargs...])')
20519
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1101
def revset(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1102
    """Execute a revision set query. See
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
  1103
    :hg:`help revset`."""
20519
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1104
    if not len(args) > 0:
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1105
        # i18n: "revset" is a keyword
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1106
        raise error.ParseError(_("revset expects one or more arguments"))
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1107
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1108
    raw = evalstring(context, mapping, args[0])
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1109
    ctx = context.resource(mapping, 'ctx')
24337
696ab1a24ae0 templater: replace 'ctx._repo' with 'ctx.repo()'
Matt Harbison <matt_harbison@yahoo.com>
parents: 24306
diff changeset
  1110
    repo = ctx.repo()
20519
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1111
22304
5678b0e3608f templater: enable alias predicates to be used in "revset()" function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 21960
diff changeset
  1112
    def query(expr):
33554
2943141f5e07 revset: pass repo when passing ui
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33033
diff changeset
  1113
        m = revsetmod.match(repo.ui, expr, repo=repo)
24114
fafd9a1284cf revset: make match function initiate query from full set by default
Yuya Nishihara <yuya@tcha.org>
parents: 23167
diff changeset
  1114
        return m(repo)
22304
5678b0e3608f templater: enable alias predicates to be used in "revset()" function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 21960
diff changeset
  1115
20519
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1116
    if len(args) > 1:
28333
41373244f4e5 templater: fix revset() to evaluate format arguments eagerly
Yuya Nishihara <yuya@tcha.org>
parents: 28332
diff changeset
  1117
        formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
31044
0b8356705de6 revset: split language services to revsetlang module (API)
Yuya Nishihara <yuya@tcha.org>
parents: 30630
diff changeset
  1118
        revs = query(revsetlang.formatspec(raw, *formatargs))
28178
96f2d50fb9f6 templater: factor out type conversion of revset() result
Yuya Nishihara <yuya@tcha.org>
parents: 27940
diff changeset
  1119
        revs = list(revs)
20519
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1120
    else:
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1121
        cache = context.resource(mapping, 'cache')
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1122
        revsetcache = cache.setdefault("revsetcache", {})
20519
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1123
        if raw in revsetcache:
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1124
            revs = revsetcache[raw]
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1125
        else:
22304
5678b0e3608f templater: enable alias predicates to be used in "revset()" function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 21960
diff changeset
  1126
            revs = query(raw)
28178
96f2d50fb9f6 templater: factor out type conversion of revset() result
Yuya Nishihara <yuya@tcha.org>
parents: 27940
diff changeset
  1127
            revs = list(revs)
20519
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1128
            revsetcache[raw] = revs
36624
2da414105809 templatekw: switch revset() to new API
Yuya Nishihara <yuya@tcha.org>
parents: 36620
diff changeset
  1129
    return templatekw.showrevslist(context, mapping, "revision", revs)
20519
cda9d2b6beab template: add revset() template function
Durham Goode <durham@fb.com>
parents: 20518
diff changeset
  1130
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1131
@templatefunc('rstdoc(text, style)')
18747
f5db3092790f hgweb: generate HTML documentation
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 18582
diff changeset
  1132
def rstdoc(context, mapping, args):
30342
318a24b52eeb spelling: fixes of non-dictionary words
Mads Kiilerich <madski@unity3d.com>
parents: 30232
diff changeset
  1133
    """Format reStructuredText."""
18747
f5db3092790f hgweb: generate HTML documentation
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 18582
diff changeset
  1134
    if len(args) != 2:
f5db3092790f hgweb: generate HTML documentation
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 18582
diff changeset
  1135
        # i18n: "rstdoc" is a keyword
f5db3092790f hgweb: generate HTML documentation
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 18582
diff changeset
  1136
        raise error.ParseError(_("rstdoc expects two arguments"))
f5db3092790f hgweb: generate HTML documentation
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 18582
diff changeset
  1137
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1138
    text = evalstring(context, mapping, args[0])
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1139
    style = evalstring(context, mapping, args[1])
18747
f5db3092790f hgweb: generate HTML documentation
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 18582
diff changeset
  1140
19079
1e433b5457fd hgweb: make help verbose again (issue3899)
Alexander Plavin <me@aplavin.ru>
parents: 19058
diff changeset
  1141
    return minirst.format(text, style=style, keep=['verbose'])
18747
f5db3092790f hgweb: generate HTML documentation
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 18582
diff changeset
  1142
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
  1143
@templatefunc('separate(sep, args)', argspec='sep *args')
29085
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1144
def separate(context, mapping, args):
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1145
    """Add a separator between non-empty arguments."""
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
  1146
    if 'sep' not in args:
29085
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1147
        # i18n: "separate" is a keyword
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1148
        raise error.ParseError(_("separate expects at least one argument"))
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1149
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
  1150
    sep = evalstring(context, mapping, args['sep'])
29085
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1151
    first = True
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
  1152
    for arg in args['args']:
29085
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1153
        argstr = evalstring(context, mapping, arg)
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1154
        if not argstr:
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1155
            continue
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1156
        if first:
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1157
            first = False
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1158
        else:
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1159
            yield sep
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1160
        yield argstr
df838803c1d4 templater: add separate() template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 28957
diff changeset
  1161
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1162
@templatefunc('shortest(node, minlength=4)')
20369
9c6b86dd2ed2 template: add shortest(node) template function
Durham Goode <durham@fb.com>
parents: 20312
diff changeset
  1163
def shortest(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1164
    """Obtain the shortest representation of
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
  1165
    a node."""
20369
9c6b86dd2ed2 template: add shortest(node) template function
Durham Goode <durham@fb.com>
parents: 20312
diff changeset
  1166
    if not (1 <= len(args) <= 2):
23112
3226ed457928 i18n: add i18n comment to error messages of template functions
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22844
diff changeset
  1167
        # i18n: "shortest" is a keyword
20369
9c6b86dd2ed2 template: add shortest(node) template function
Durham Goode <durham@fb.com>
parents: 20312
diff changeset
  1168
        raise error.ParseError(_("shortest() expects one or two arguments"))
9c6b86dd2ed2 template: add shortest(node) template function
Durham Goode <durham@fb.com>
parents: 20312
diff changeset
  1169
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1170
    node = evalstring(context, mapping, args[0])
20369
9c6b86dd2ed2 template: add shortest(node) template function
Durham Goode <durham@fb.com>
parents: 20312
diff changeset
  1171
9c6b86dd2ed2 template: add shortest(node) template function
Durham Goode <durham@fb.com>
parents: 20312
diff changeset
  1172
    minlength = 4
9c6b86dd2ed2 template: add shortest(node) template function
Durham Goode <durham@fb.com>
parents: 20312
diff changeset
  1173
    if len(args) > 1:
28346
542d200bd261 templater: fix shortest() to evaluate int argument and handle error
Yuya Nishihara <yuya@tcha.org>
parents: 28345
diff changeset
  1174
        minlength = evalinteger(context, mapping, args[1],
542d200bd261 templater: fix shortest() to evaluate int argument and handle error
Yuya Nishihara <yuya@tcha.org>
parents: 28345
diff changeset
  1175
                                # i18n: "shortest" is a keyword
542d200bd261 templater: fix shortest() to evaluate int argument and handle error
Yuya Nishihara <yuya@tcha.org>
parents: 28345
diff changeset
  1176
                                _("shortest() expects an integer minlength"))
20369
9c6b86dd2ed2 template: add shortest(node) template function
Durham Goode <durham@fb.com>
parents: 20312
diff changeset
  1177
30232
362740e05460 templater: use unfiltered changelog to calculate shortest() at constant time
Yuya Nishihara <yuya@tcha.org>
parents: 30231
diff changeset
  1178
    # _partialmatch() of filtered changelog could take O(len(repo)) time,
362740e05460 templater: use unfiltered changelog to calculate shortest() at constant time
Yuya Nishihara <yuya@tcha.org>
parents: 30231
diff changeset
  1179
    # which would be unacceptably slow. so we look for hash collision in
362740e05460 templater: use unfiltered changelog to calculate shortest() at constant time
Yuya Nishihara <yuya@tcha.org>
parents: 30231
diff changeset
  1180
    # unfiltered space, which means some hashes may be slightly longer.
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1181
    cl = context.resource(mapping, 'ctx')._repo.unfiltered().changelog
34257
448725a2ef73 templater: extract shortest() logic from template function
Martin von Zweigbergk <martinvonz@google.com>
parents: 34154
diff changeset
  1182
    return cl.shortest(node, minlength)
20369
9c6b86dd2ed2 template: add shortest(node) template function
Durham Goode <durham@fb.com>
parents: 20312
diff changeset
  1183
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1184
@templatefunc('strip(text[, chars])')
19330
867b9957d895 templater: add strip function with chars as an extra argument
Alexander Plavin <me@aplavin.ru>
parents: 19228
diff changeset
  1185
def strip(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1186
    """Strip characters from a string. By default,
26106
c568c4db036f templatefilters: remove redundant 'date' and 'strip' filters
Yuya Nishihara <yuya@tcha.org>
parents: 26105
diff changeset
  1187
    strips all leading and trailing whitespace."""
19330
867b9957d895 templater: add strip function with chars as an extra argument
Alexander Plavin <me@aplavin.ru>
parents: 19228
diff changeset
  1188
    if not (1 <= len(args) <= 2):
23112
3226ed457928 i18n: add i18n comment to error messages of template functions
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 22844
diff changeset
  1189
        # i18n: "strip" is a keyword
19330
867b9957d895 templater: add strip function with chars as an extra argument
Alexander Plavin <me@aplavin.ru>
parents: 19228
diff changeset
  1190
        raise error.ParseError(_("strip expects one or two arguments"))
867b9957d895 templater: add strip function with chars as an extra argument
Alexander Plavin <me@aplavin.ru>
parents: 19228
diff changeset
  1191
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1192
    text = evalstring(context, mapping, args[0])
19330
867b9957d895 templater: add strip function with chars as an extra argument
Alexander Plavin <me@aplavin.ru>
parents: 19228
diff changeset
  1193
    if len(args) == 2:
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1194
        chars = evalstring(context, mapping, args[1])
19330
867b9957d895 templater: add strip function with chars as an extra argument
Alexander Plavin <me@aplavin.ru>
parents: 19228
diff changeset
  1195
        return text.strip(chars)
867b9957d895 templater: add strip function with chars as an extra argument
Alexander Plavin <me@aplavin.ru>
parents: 19228
diff changeset
  1196
    return text.strip()
867b9957d895 templater: add strip function with chars as an extra argument
Alexander Plavin <me@aplavin.ru>
parents: 19228
diff changeset
  1197
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1198
@templatefunc('sub(pattern, replacement, expression)')
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
  1199
def sub(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1200
    """Perform text substitution
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
  1201
    using regular expressions."""
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
  1202
    if len(args) != 3:
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
  1203
        # i18n: "sub" is a keyword
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
  1204
        raise error.ParseError(_("sub expects three arguments"))
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
  1205
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1206
    pat = evalstring(context, mapping, args[0])
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1207
    rpl = evalstring(context, mapping, args[1])
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1208
    src = evalstring(context, mapping, args[2])
26188
662ea52d5dca templater: catch regexp error at sub() function
Yuya Nishihara <yuya@tcha.org>
parents: 26128
diff changeset
  1209
    try:
662ea52d5dca templater: catch regexp error at sub() function
Yuya Nishihara <yuya@tcha.org>
parents: 26128
diff changeset
  1210
        patre = re.compile(pat)
662ea52d5dca templater: catch regexp error at sub() function
Yuya Nishihara <yuya@tcha.org>
parents: 26128
diff changeset
  1211
    except re.error:
662ea52d5dca templater: catch regexp error at sub() function
Yuya Nishihara <yuya@tcha.org>
parents: 26128
diff changeset
  1212
        # i18n: "sub" is a keyword
662ea52d5dca templater: catch regexp error at sub() function
Yuya Nishihara <yuya@tcha.org>
parents: 26128
diff changeset
  1213
        raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
662ea52d5dca templater: catch regexp error at sub() function
Yuya Nishihara <yuya@tcha.org>
parents: 26128
diff changeset
  1214
    try:
662ea52d5dca templater: catch regexp error at sub() function
Yuya Nishihara <yuya@tcha.org>
parents: 26128
diff changeset
  1215
        yield patre.sub(rpl, src)
662ea52d5dca templater: catch regexp error at sub() function
Yuya Nishihara <yuya@tcha.org>
parents: 26128
diff changeset
  1216
    except re.error:
662ea52d5dca templater: catch regexp error at sub() function
Yuya Nishihara <yuya@tcha.org>
parents: 26128
diff changeset
  1217
        # i18n: "sub" is a keyword
662ea52d5dca templater: catch regexp error at sub() function
Yuya Nishihara <yuya@tcha.org>
parents: 26128
diff changeset
  1218
        raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
19390
3af3a165db18 templater: sort functions alphabetically, as filters are
Alexander Plavin <me@aplavin.ru>
parents: 19330
diff changeset
  1219
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1220
@templatefunc('startswith(pattern, text)')
21821
4a445dc5abff templater: introduce startswith function
Ryan McElroy <rmcelroy@fb.com>
parents: 21798
diff changeset
  1221
def startswith(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1222
    """Returns the value from the "text" argument
24586
90e3f5d22dad templater: add consistent docstrings to functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24337
diff changeset
  1223
    if it begins with the content from the "pattern" argument."""
21821
4a445dc5abff templater: introduce startswith function
Ryan McElroy <rmcelroy@fb.com>
parents: 21798
diff changeset
  1224
    if len(args) != 2:
21960
2896d450fec4 templater: add i18n comments to error messages of newly added functions
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 21846
diff changeset
  1225
        # i18n: "startswith" is a keyword
21821
4a445dc5abff templater: introduce startswith function
Ryan McElroy <rmcelroy@fb.com>
parents: 21798
diff changeset
  1226
        raise error.ParseError(_("startswith expects two arguments"))
4a445dc5abff templater: introduce startswith function
Ryan McElroy <rmcelroy@fb.com>
parents: 21798
diff changeset
  1227
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1228
    patn = evalstring(context, mapping, args[0])
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1229
    text = evalstring(context, mapping, args[1])
21821
4a445dc5abff templater: introduce startswith function
Ryan McElroy <rmcelroy@fb.com>
parents: 21798
diff changeset
  1230
    if text.startswith(patn):
4a445dc5abff templater: introduce startswith function
Ryan McElroy <rmcelroy@fb.com>
parents: 21798
diff changeset
  1231
        return text
4a445dc5abff templater: introduce startswith function
Ryan McElroy <rmcelroy@fb.com>
parents: 21798
diff changeset
  1232
    return ''
4a445dc5abff templater: introduce startswith function
Ryan McElroy <rmcelroy@fb.com>
parents: 21798
diff changeset
  1233
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1234
@templatefunc('word(number, text[, separator])')
21846
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1235
def word(context, mapping, args):
28696
efa192203623 templater: use templatefunc to mark a function as template function
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28695
diff changeset
  1236
    """Return the nth word from a string."""
21846
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1237
    if not (2 <= len(args) <= 3):
21960
2896d450fec4 templater: add i18n comments to error messages of newly added functions
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 21846
diff changeset
  1238
        # i18n: "word" is a keyword
21846
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1239
        raise error.ParseError(_("word expects two or three arguments, got %d")
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1240
                               % len(args))
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1241
28343
a6c2310b3827 templater: factor out function that evaluates argument as integer
Yuya Nishihara <yuya@tcha.org>
parents: 28334
diff changeset
  1242
    num = evalinteger(context, mapping, args[0],
a6c2310b3827 templater: factor out function that evaluates argument as integer
Yuya Nishihara <yuya@tcha.org>
parents: 28334
diff changeset
  1243
                      # i18n: "word" is a keyword
a6c2310b3827 templater: factor out function that evaluates argument as integer
Yuya Nishihara <yuya@tcha.org>
parents: 28334
diff changeset
  1244
                      _("word expects an integer index"))
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1245
    text = evalstring(context, mapping, args[1])
21846
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1246
    if len(args) == 3:
28348
ccedb17a5657 templater: factor out thin helper that evaluates argument as string
Yuya Nishihara <yuya@tcha.org>
parents: 28346
diff changeset
  1247
        splitter = evalstring(context, mapping, args[2])
21846
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1248
    else:
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1249
        splitter = None
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1250
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1251
    tokens = text.split(splitter)
26502
4ca98a389152 templater: protect word() from crashing on out of range negative value
Matt Harbison <matt_harbison@yahoo.com>
parents: 25815
diff changeset
  1252
    if num >= len(tokens) or num < -len(tokens):
21846
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1253
        return ''
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1254
    else:
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1255
        return tokens[num]
8f23f8096606 templater: introduce word function
Ryan McElroy <rmcelroy@fb.com>
parents: 21822
diff changeset
  1256
25001
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
  1257
# methods to interpret function arguments or inner expressions (e.g. {_(x)})
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
  1258
exprmethods = {
25002
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
  1259
    "integer": lambda e, c: (runinteger, e[1]),
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1260
    "string": lambda e, c: (runstring, e[1]),
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1261
    "symbol": lambda e, c: (runsymbol, e[1]),
25596
c1975809a6b5 templater: take any string literals as template, but not for rawstring (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25595
diff changeset
  1262
    "template": buildtemplate,
25001
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
  1263
    "group": lambda e, c: compileexp(e[1], c, exprmethods),
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
  1264
    ".": buildmember,
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1265
    "|": buildfilter,
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1266
    "%": buildmap,
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1267
    "func": buildfunc,
31885
d18b624c1c06 templater: add parsing rule for key-value pair
Yuya Nishihara <yuya@tcha.org>
parents: 31884
diff changeset
  1268
    "keyvalue": buildkeyvaluepair,
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1269
    "+": lambda e, c: buildarithmetic(e, c, lambda a, b: a + b),
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1270
    "-": lambda e, c: buildarithmetic(e, c, lambda a, b: a - b),
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1271
    "negate": buildnegate,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1272
    "*": lambda e, c: buildarithmetic(e, c, lambda a, b: a * b),
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
  1273
    "/": lambda e, c: buildarithmetic(e, c, lambda a, b: a // b),
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1274
    }
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1275
25001
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
  1276
# methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
  1277
methods = exprmethods.copy()
25002
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
  1278
methods["integer"] = exprmethods["symbol"]  # '{1}' as variable
25001
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
  1279
28912
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1280
class _aliasrules(parser.basealiasrules):
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1281
    """Parsing and expansion rule set of template aliases"""
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1282
    _section = _('template alias')
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1283
    _parse = staticmethod(_parseexpr)
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1284
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1285
    @staticmethod
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1286
    def _trygetfunc(tree):
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1287
        """Return (name, args) if tree is func(...) or ...|filter; otherwise
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1288
        None"""
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1289
        if tree[0] == 'func' and tree[1][0] == 'symbol':
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1290
            return tree[1][1], getlist(tree[2])
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1291
        if tree[0] == '|' and tree[2][0] == 'symbol':
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1292
            return tree[2][1], [tree[1]]
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1293
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1294
def expandaliases(tree, aliases):
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1295
    """Return new tree of aliases are expanded"""
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1296
    aliasmap = _aliasrules.buildmap(aliases)
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1297
    return _aliasrules.expand(aliasmap, tree)
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
  1298
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1299
# template engine
1901
c64bef3d7043 use safer string parser for template engine.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1900
diff changeset
  1300
8360
acc202b71619 templater: provide the standard template filters by default
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8312
diff changeset
  1301
stringify = templatefilters.stringify
7107
125c8fedcbe0 Allow hgweb to search for templates in more than one path.
Brendan Cully <brendan@kublai.com>
parents: 6783
diff changeset
  1302
10850
a63391e26284 templater: use recursive flattening
Matt Mackall <mpm@selenic.com>
parents: 10849
diff changeset
  1303
def _flatten(thing):
a63391e26284 templater: use recursive flattening
Matt Mackall <mpm@selenic.com>
parents: 10849
diff changeset
  1304
    '''yield a single stream from a possibly nested set of iterators'''
31880
a0f2d83f8083 templater: remove __iter__() from _hybrid, resolve it explicitly
Yuya Nishihara <yuya@tcha.org>
parents: 31850
diff changeset
  1305
    thing = templatekw.unwraphybrid(thing)
32988
11c0bb4ccc76 py3: replace str with bytes in isinstance()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32891
diff changeset
  1306
    if isinstance(thing, bytes):
10850
a63391e26284 templater: use recursive flattening
Matt Mackall <mpm@selenic.com>
parents: 10849
diff changeset
  1307
        yield thing
34723
b13c95919ff5 templater: explode if we try to emit a str
Augie Fackler <augie@google.com>
parents: 34715
diff changeset
  1308
    elif isinstance(thing, str):
b13c95919ff5 templater: explode if we try to emit a str
Augie Fackler <augie@google.com>
parents: 34715
diff changeset
  1309
        # We can only hit this on Python 3, and it's here to guard
b13c95919ff5 templater: explode if we try to emit a str
Augie Fackler <augie@google.com>
parents: 34715
diff changeset
  1310
        # against infinite recursion.
b13c95919ff5 templater: explode if we try to emit a str
Augie Fackler <augie@google.com>
parents: 34715
diff changeset
  1311
        raise error.ProgrammingError('Mercurial IO including templates is done'
b13c95919ff5 templater: explode if we try to emit a str
Augie Fackler <augie@google.com>
parents: 34715
diff changeset
  1312
                                     ' with bytes, not strings')
29826
0d5cc0c18b4e templater: make it clearer that _flatten() omits None
Yuya Nishihara <yuya@tcha.org>
parents: 29823
diff changeset
  1313
    elif thing is None:
0d5cc0c18b4e templater: make it clearer that _flatten() omits None
Yuya Nishihara <yuya@tcha.org>
parents: 29823
diff changeset
  1314
        pass
14944
e2c413bde8a5 globally: use safehasattr(x, '__iter__') instead of hasattr(x, '__iter__')
Augie Fackler <durin42@gmail.com>
parents: 14943
diff changeset
  1315
    elif not util.safehasattr(thing, '__iter__'):
32992
8779d35c168d py3: use pycompat.bytestr() in place of str()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32988
diff changeset
  1316
        yield pycompat.bytestr(thing)
10852
0d50586a9d31 templater: raise nested functions
Matt Mackall <mpm@selenic.com>
parents: 10850
diff changeset
  1317
    else:
10850
a63391e26284 templater: use recursive flattening
Matt Mackall <mpm@selenic.com>
parents: 10849
diff changeset
  1318
        for i in thing:
31880
a0f2d83f8083 templater: remove __iter__() from _hybrid, resolve it explicitly
Yuya Nishihara <yuya@tcha.org>
parents: 31850
diff changeset
  1319
            i = templatekw.unwraphybrid(i)
32988
11c0bb4ccc76 py3: replace str with bytes in isinstance()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32891
diff changeset
  1320
            if isinstance(i, bytes):
10850
a63391e26284 templater: use recursive flattening
Matt Mackall <mpm@selenic.com>
parents: 10849
diff changeset
  1321
                yield i
29826
0d5cc0c18b4e templater: make it clearer that _flatten() omits None
Yuya Nishihara <yuya@tcha.org>
parents: 29823
diff changeset
  1322
            elif i is None:
0d5cc0c18b4e templater: make it clearer that _flatten() omits None
Yuya Nishihara <yuya@tcha.org>
parents: 29823
diff changeset
  1323
                pass
14944
e2c413bde8a5 globally: use safehasattr(x, '__iter__') instead of hasattr(x, '__iter__')
Augie Fackler <durin42@gmail.com>
parents: 14943
diff changeset
  1324
            elif not util.safehasattr(i, '__iter__'):
32992
8779d35c168d py3: use pycompat.bytestr() in place of str()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32988
diff changeset
  1325
                yield pycompat.bytestr(i)
29826
0d5cc0c18b4e templater: make it clearer that _flatten() omits None
Yuya Nishihara <yuya@tcha.org>
parents: 29823
diff changeset
  1326
            else:
10850
a63391e26284 templater: use recursive flattening
Matt Mackall <mpm@selenic.com>
parents: 10849
diff changeset
  1327
                for j in _flatten(i):
a63391e26284 templater: use recursive flattening
Matt Mackall <mpm@selenic.com>
parents: 10849
diff changeset
  1328
                    yield j
a63391e26284 templater: use recursive flattening
Matt Mackall <mpm@selenic.com>
parents: 10849
diff changeset
  1329
24988
e8ff0b09acac templater: rename parsestring() to unquotestring() (API)
Yuya Nishihara <yuya@tcha.org>
parents: 24987
diff changeset
  1330
def unquotestring(s):
28630
bf35644b9f3a templater: relax unquotestring() to fall back to bare string
Yuya Nishihara <yuya@tcha.org>
parents: 28628
diff changeset
  1331
    '''unwrap quotes if any; otherwise returns unmodified string'''
28687
29c249dfb4ef templater: do not strip non-quote characters from template config
Yuya Nishihara <yuya@tcha.org>
parents: 28630
diff changeset
  1332
    if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
28630
bf35644b9f3a templater: relax unquotestring() to fall back to bare string
Yuya Nishihara <yuya@tcha.org>
parents: 28628
diff changeset
  1333
        return s
25696
c1cac25ad1a6 templater: remove workaround for escaped quoted string in quoted template
Yuya Nishihara <yuya@tcha.org>
parents: 25695
diff changeset
  1334
    return s[1:-1]
1896
f8f818a04f5b move hgweb template code out to templater
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
  1335
8218
e61cb2813d2a templater: separate template management and actual string processing
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
  1336
class engine(object):
1909
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1337
    '''template expansion engine.
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1338
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1339
    template expansion works like this. a map file contains key=value
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1340
    pairs. if value is quoted, it is treated as string. otherwise, it
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1341
    is treated as name of template file.
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1342
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1343
    templater is asked to expand a key in map. it looks up key, and
4334
66a3fe30f9fc minor typo fix in templater's docstring
TK Soh <teekaysoh@yahoo.com>
parents: 3904
diff changeset
  1344
    looks for strings like this: {foo}. it expands {foo} by looking up
1909
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1345
    foo in map, and substituting it. expansion is recursive: it stops
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1346
    when there is no more {foo} to replace.
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1347
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1348
    expansion also allows formatting and filtering.
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1349
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1350
    format uses key to expand each item in list. syntax is
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1351
    {key%format}.
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1352
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1353
    filter uses function to transform value. syntax is
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1354
    {key|filter1|filter2|...}.'''
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
  1355
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1356
    def __init__(self, loader, filters=None, defaults=None, resources=None,
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1357
                 aliases=()):
10848
01346cea5485 templater: privatize class variables
Matt Mackall <mpm@selenic.com>
parents: 10847
diff changeset
  1358
        self._loader = loader
26330
ec4f3755d997 templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26234
diff changeset
  1359
        if filters is None:
ec4f3755d997 templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26234
diff changeset
  1360
            filters = {}
10848
01346cea5485 templater: privatize class variables
Matt Mackall <mpm@selenic.com>
parents: 10847
diff changeset
  1361
        self._filters = filters
26331
2c6a741bf05e templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26330
diff changeset
  1362
        if defaults is None:
2c6a741bf05e templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26330
diff changeset
  1363
            defaults = {}
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1364
        if resources is None:
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1365
            resources = {}
10848
01346cea5485 templater: privatize class variables
Matt Mackall <mpm@selenic.com>
parents: 10847
diff changeset
  1366
        self._defaults = defaults
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1367
        self._resources = resources
28957
d813132ea361 templater: load and expand aliases by template engine (API) (issue4842)
Yuya Nishihara <yuya@tcha.org>
parents: 28956
diff changeset
  1368
        self._aliasmap = _aliasrules.buildmap(aliases)
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
  1369
        self._cache = {}  # key: (func, data)
8218
e61cb2813d2a templater: separate template management and actual string processing
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
  1370
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1371
    def symbol(self, mapping, key):
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1372
        """Resolve symbol to value or function; None if nothing found"""
35474
a33be093ec62 templater: look up symbols/resources as if they were separated (issue5699)
Yuya Nishihara <yuya@tcha.org>
parents: 35472
diff changeset
  1373
        v = None
a33be093ec62 templater: look up symbols/resources as if they were separated (issue5699)
Yuya Nishihara <yuya@tcha.org>
parents: 35472
diff changeset
  1374
        if key not in self._resources:
a33be093ec62 templater: look up symbols/resources as if they were separated (issue5699)
Yuya Nishihara <yuya@tcha.org>
parents: 35472
diff changeset
  1375
            v = mapping.get(key)
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1376
        if v is None:
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1377
            v = self._defaults.get(key)
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1378
        return v
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1379
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1380
    def resource(self, mapping, key):
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1381
        """Return internal data (e.g. cache) used for keyword/function
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1382
        evaluation"""
35474
a33be093ec62 templater: look up symbols/resources as if they were separated (issue5699)
Yuya Nishihara <yuya@tcha.org>
parents: 35472
diff changeset
  1383
        v = None
a33be093ec62 templater: look up symbols/resources as if they were separated (issue5699)
Yuya Nishihara <yuya@tcha.org>
parents: 35472
diff changeset
  1384
        if key in self._resources:
a33be093ec62 templater: look up symbols/resources as if they were separated (issue5699)
Yuya Nishihara <yuya@tcha.org>
parents: 35472
diff changeset
  1385
            v = mapping.get(key)
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1386
        if v is None:
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1387
            v = self._resources.get(key)
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1388
        if v is None:
36474
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36473
diff changeset
  1389
            raise ResourceUnavailable(_('template resource not available: %s')
717a279c0c21 templater: specialize ResourceUnavailable error so that it can be caught
Yuya Nishihara <yuya@tcha.org>
parents: 36473
diff changeset
  1390
                                      % key)
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1391
        return v
35471
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35421
diff changeset
  1392
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1393
    def _load(self, t):
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1394
        '''load, parse, and cache a template'''
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1395
        if t not in self._cache:
27940
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
  1396
            # put poison to cut recursion while compiling 't'
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
  1397
            self._cache[t] = (_runrecursivesymbol, t)
27940
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
  1398
            try:
28956
eea98190ed73 templater: inline compiletemplate() function into engine
Yuya Nishihara <yuya@tcha.org>
parents: 28954
diff changeset
  1399
                x = parse(self._loader(t))
28957
d813132ea361 templater: load and expand aliases by template engine (API) (issue4842)
Yuya Nishihara <yuya@tcha.org>
parents: 28956
diff changeset
  1400
                if self._aliasmap:
d813132ea361 templater: load and expand aliases by template engine (API) (issue4842)
Yuya Nishihara <yuya@tcha.org>
parents: 28956
diff changeset
  1401
                    x = _aliasrules.expand(self._aliasmap, x)
28956
eea98190ed73 templater: inline compiletemplate() function into engine
Yuya Nishihara <yuya@tcha.org>
parents: 28954
diff changeset
  1402
                self._cache[t] = compileexp(x, self, methods)
27940
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
  1403
            except: # re-raises
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
  1404
                del self._cache[t]
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
  1405
                raise
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1406
        return self._cache[t]
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
  1407
10853
b6f6d9fd53d6 templater: drop raw method
Matt Mackall <mpm@selenic.com>
parents: 10852
diff changeset
  1408
    def process(self, t, mapping):
b6f6d9fd53d6 templater: drop raw method
Matt Mackall <mpm@selenic.com>
parents: 10852
diff changeset
  1409
        '''Perform expansion. t is name of map element to expand.
b6f6d9fd53d6 templater: drop raw method
Matt Mackall <mpm@selenic.com>
parents: 10852
diff changeset
  1410
        mapping contains added elements for use during expansion. Is a
b6f6d9fd53d6 templater: drop raw method
Matt Mackall <mpm@selenic.com>
parents: 10852
diff changeset
  1411
        generator.'''
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
  1412
        func, data = self._load(t)
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
  1413
        return _flatten(func(self, mapping, data))
8218
e61cb2813d2a templater: separate template management and actual string processing
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
  1414
8361
d8c5a7f25a40 templater: make the templating engine pluggable to some extent
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8360
diff changeset
  1415
engines = {'default': engine}
d8c5a7f25a40 templater: make the templating engine pluggable to some extent
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8360
diff changeset
  1416
19125
6ba6e345961e templater: show the style list when I try to use a wrong one
Iulian Stana <julian.stana@gmail.com>
parents: 19079
diff changeset
  1417
def stylelist():
22634
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1418
    paths = templatepaths()
20312
268a5ab5c27b templater: selecting a style with no templates does not crash (issue4140)
Simon Heimberg <simohe@besonet.ch>
parents: 20067
diff changeset
  1419
    if not paths:
268a5ab5c27b templater: selecting a style with no templates does not crash (issue4140)
Simon Heimberg <simohe@besonet.ch>
parents: 20067
diff changeset
  1420
        return _('no templates found, try `hg debuginstall` for more info')
27637
b502138f5faa cleanup: remove superfluous space after space after equals (python)
timeless <timeless@mozdev.org>
parents: 27293
diff changeset
  1421
    dirlist = os.listdir(paths[0])
19125
6ba6e345961e templater: show the style list when I try to use a wrong one
Iulian Stana <julian.stana@gmail.com>
parents: 19079
diff changeset
  1422
    stylelist = []
6ba6e345961e templater: show the style list when I try to use a wrong one
Iulian Stana <julian.stana@gmail.com>
parents: 19079
diff changeset
  1423
    for file in dirlist:
6ba6e345961e templater: show the style list when I try to use a wrong one
Iulian Stana <julian.stana@gmail.com>
parents: 19079
diff changeset
  1424
        split = file.split(".")
28403
d2e154dddb6e templater: ignore orig/rej files
timeless <timeless@mozdev.org>
parents: 28384
diff changeset
  1425
        if split[-1] in ('orig', 'rej'):
d2e154dddb6e templater: ignore orig/rej files
timeless <timeless@mozdev.org>
parents: 28384
diff changeset
  1426
            continue
19125
6ba6e345961e templater: show the style list when I try to use a wrong one
Iulian Stana <julian.stana@gmail.com>
parents: 19079
diff changeset
  1427
        if split[0] == "map-cmdline":
6ba6e345961e templater: show the style list when I try to use a wrong one
Iulian Stana <julian.stana@gmail.com>
parents: 19079
diff changeset
  1428
            stylelist.append(split[1])
19127
d982edcfe7f0 templater: fix output instability from gsoc patches
Augie Fackler <raf@durin42.com>
parents: 19125
diff changeset
  1429
    return ", ".join(sorted(stylelist))
19125
6ba6e345961e templater: show the style list when I try to use a wrong one
Iulian Stana <julian.stana@gmail.com>
parents: 19079
diff changeset
  1430
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1431
def _readmapfile(mapfile):
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1432
    """Load template elements from the given map file"""
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1433
    if not os.path.exists(mapfile):
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1434
        raise error.Abort(_("style '%s' not found") % mapfile,
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1435
                          hint=_("available styles: %s") % stylelist())
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1436
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1437
    base = os.path.dirname(mapfile)
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1438
    conf = config.config(includepaths=templatepaths())
34714
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
  1439
    conf.read(mapfile, remap={'': 'templates'})
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1440
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1441
    cache = {}
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1442
    tmap = {}
34715
f17a0e18c47e templater: load aliases from [templatealias] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34714
diff changeset
  1443
    aliases = []
34712
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1444
34714
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
  1445
    val = conf.get('templates', '__base__')
34712
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1446
    if val and val[0] not in "'\"":
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1447
        # treat as a pointer to a base class for this style
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1448
        path = util.normpath(os.path.join(base, val))
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1449
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1450
        # fallback check in template paths
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1451
        if not os.path.exists(path):
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1452
            for p in templatepaths():
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1453
                p2 = util.normpath(os.path.join(p, val))
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1454
                if os.path.isfile(p2):
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1455
                    path = p2
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1456
                    break
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1457
                p3 = util.normpath(os.path.join(p2, "map"))
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1458
                if os.path.isfile(p3):
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1459
                    path = p3
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1460
                    break
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1461
34715
f17a0e18c47e templater: load aliases from [templatealias] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34714
diff changeset
  1462
        cache, tmap, aliases = _readmapfile(path)
34712
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1463
34714
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
  1464
    for key, val in conf['templates'].items():
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1465
        if not val:
34714
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
  1466
            raise error.ParseError(_('missing value'),
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
  1467
                                   conf.source('templates', key))
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1468
        if val[0] in "'\"":
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1469
            if val[0] != val[-1]:
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1470
                raise error.ParseError(_('unmatched quotes'),
34714
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
  1471
                                       conf.source('templates', key))
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1472
            cache[key] = unquotestring(val)
34712
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
  1473
        elif key != '__base__':
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1474
            val = 'default', val
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1475
            if ':' in val[1]:
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1476
                val = val[1].split(':', 1)
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1477
            tmap[key] = val[0], os.path.join(base, val[1])
34715
f17a0e18c47e templater: load aliases from [templatealias] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34714
diff changeset
  1478
    aliases.extend(conf['templatealias'].items())
f17a0e18c47e templater: load aliases from [templatealias] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34714
diff changeset
  1479
    return cache, tmap, aliases
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
  1480
8218
e61cb2813d2a templater: separate template management and actual string processing
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
  1481
class templater(object):
e61cb2813d2a templater: separate template management and actual string processing
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
  1482
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1483
    def __init__(self, filters=None, defaults=None, resources=None,
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1484
                 cache=None, aliases=(), minchunk=1024, maxchunk=65536):
35485
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1485
        """Create template engine optionally with preloaded template fragments
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1486
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1487
        - ``filters``: a dict of functions to transform a value into another.
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1488
        - ``defaults``: a dict of symbol values/functions; may be overridden
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1489
          by a ``mapping`` dict.
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1490
        - ``resources``: a dict of internal data (e.g. cache), inaccessible
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1491
          from user template; may be overridden by a ``mapping`` dict.
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1492
        - ``cache``: a dict of preloaded template fragments.
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1493
        - ``aliases``: a list of alias (name, replacement) pairs.
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1494
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1495
        self.cache may be updated later to register additional template
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1496
        fragments.
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35474
diff changeset
  1497
        """
26332
66221730d372 templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26331
diff changeset
  1498
        if filters is None:
66221730d372 templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26331
diff changeset
  1499
            filters = {}
26333
727d57e94cda templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26332
diff changeset
  1500
        if defaults is None:
727d57e94cda templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26332
diff changeset
  1501
            defaults = {}
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1502
        if resources is None:
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1503
            resources = {}
26334
0a5a774f5956 templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26333
diff changeset
  1504
        if cache is None:
0a5a774f5956 templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26333
diff changeset
  1505
            cache = {}
1975
6e1a8ea5d717 Duplicate cache when creating templater.
Shun-ichi Goto <shunichi.goto@gmail.com>
parents: 1964
diff changeset
  1506
        self.cache = cache.copy()
1896
f8f818a04f5b move hgweb template code out to templater
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
  1507
        self.map = {}
8360
acc202b71619 templater: provide the standard template filters by default
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8312
diff changeset
  1508
        self.filters = templatefilters.filters.copy()
acc202b71619 templater: provide the standard template filters by default
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8312
diff changeset
  1509
        self.filters.update(filters)
1964
778281d46bb2 fix template bug that made hgweb break.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1955
diff changeset
  1510
        self.defaults = defaults
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1511
        self._resources = {'templ': self}
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1512
        self._resources.update(resources)
28957
d813132ea361 templater: load and expand aliases by template engine (API) (issue4842)
Yuya Nishihara <yuya@tcha.org>
parents: 28956
diff changeset
  1513
        self._aliases = aliases
7396
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7107
diff changeset
  1514
        self.minchunk, self.maxchunk = minchunk, maxchunk
13187
e3b87fb34d00 templater: clarify engine caching
Matt Mackall <mpm@selenic.com>
parents: 13176
diff changeset
  1515
        self.ecache = {}
1896
f8f818a04f5b move hgweb template code out to templater
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
  1516
28954
f97a0bcfd7a1 templater: separate function to create templater from map file (API)
Yuya Nishihara <yuya@tcha.org>
parents: 28953
diff changeset
  1517
    @classmethod
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1518
    def frommapfile(cls, mapfile, filters=None, defaults=None, resources=None,
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1519
                    cache=None, minchunk=1024, maxchunk=65536):
28954
f97a0bcfd7a1 templater: separate function to create templater from map file (API)
Yuya Nishihara <yuya@tcha.org>
parents: 28953
diff changeset
  1520
        """Create templater from the specified map file"""
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1521
        t = cls(filters, defaults, resources, cache, [], minchunk, maxchunk)
34715
f17a0e18c47e templater: load aliases from [templatealias] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34714
diff changeset
  1522
        cache, tmap, aliases = _readmapfile(mapfile)
28954
f97a0bcfd7a1 templater: separate function to create templater from map file (API)
Yuya Nishihara <yuya@tcha.org>
parents: 28953
diff changeset
  1523
        t.cache.update(cache)
f97a0bcfd7a1 templater: separate function to create templater from map file (API)
Yuya Nishihara <yuya@tcha.org>
parents: 28953
diff changeset
  1524
        t.map = tmap
34715
f17a0e18c47e templater: load aliases from [templatealias] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34714
diff changeset
  1525
        t._aliases = aliases
28954
f97a0bcfd7a1 templater: separate function to create templater from map file (API)
Yuya Nishihara <yuya@tcha.org>
parents: 28953
diff changeset
  1526
        return t
1896
f8f818a04f5b move hgweb template code out to templater
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
  1527
1899
888d298ddb91 many small changes to templater.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1897
diff changeset
  1528
    def __contains__(self, key):
3637
e7639888bb2f templater: simplify cache and remove filter argument in __call__
Matt Mackall <mpm@selenic.com>
parents: 3636
diff changeset
  1529
        return key in self.cache or key in self.map
1899
888d298ddb91 many small changes to templater.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1897
diff changeset
  1530
8218
e61cb2813d2a templater: separate template management and actual string processing
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
  1531
    def load(self, t):
6783
6d824dc86907 templater: make a template a string-only iterator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6434
diff changeset
  1532
        '''Get the template for the given template name. Use a local cache.'''
16686
67964cda8701 cleanup: "not x in y" -> "x not in y"
Brodie Rao <brodie@sf.io>
parents: 14944
diff changeset
  1533
        if t not in self.cache:
1905
0c760737b996 improve template errors when something is wrong.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1904
diff changeset
  1534
            try:
14168
135e244776f0 prevent transient leaks of file handle by using new helper functions
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13665
diff changeset
  1535
                self.cache[t] = util.readfile(self.map[t][1])
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25654
diff changeset
  1536
            except KeyError as inst:
19770
0361163efbaf templater: support using templates with non-standard names from map file
Alexander Plavin <alexander@plav.in>
parents: 19390
diff changeset
  1537
                raise TemplateNotFound(_('"%s" not in template map') %
0361163efbaf templater: support using templates with non-standard names from map file
Alexander Plavin <alexander@plav.in>
parents: 19390
diff changeset
  1538
                                       inst.args[0])
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25654
diff changeset
  1539
            except IOError as inst:
36530
43e108027b0d py3: move between bytes and unicode when re-raising IOError
Yuya Nishihara <yuya@tcha.org>
parents: 36475
diff changeset
  1540
                reason = (_('template file %s: %s')
43e108027b0d py3: move between bytes and unicode when re-raising IOError
Yuya Nishihara <yuya@tcha.org>
parents: 36475
diff changeset
  1541
                          % (self.map[t][1], util.forcebytestr(inst.args[1])))
43e108027b0d py3: move between bytes and unicode when re-raising IOError
Yuya Nishihara <yuya@tcha.org>
parents: 36475
diff changeset
  1542
                raise IOError(inst.args[0], encoding.strfromlocal(reason))
6783
6d824dc86907 templater: make a template a string-only iterator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6434
diff changeset
  1543
        return self.cache[t]
1896
f8f818a04f5b move hgweb template code out to templater
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
  1544
32891
2ecce24dfcd3 templater: add simple interface for unnamed template (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32704
diff changeset
  1545
    def render(self, mapping):
2ecce24dfcd3 templater: add simple interface for unnamed template (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32704
diff changeset
  1546
        """Render the default unnamed template and return result as string"""
34353
46f45b7efa30 py3: use pycompat.strkwargs() before passing a dict as keyword argument
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34337
diff changeset
  1547
        mapping = pycompat.strkwargs(mapping)
32891
2ecce24dfcd3 templater: add simple interface for unnamed template (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32704
diff changeset
  1548
        return stringify(self('', **mapping))
2ecce24dfcd3 templater: add simple interface for unnamed template (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32704
diff changeset
  1549
10847
90f4367535a5 templater: map -> mapping
Matt Mackall <mpm@selenic.com>
parents: 10846
diff changeset
  1550
    def __call__(self, t, **mapping):
33032
4e6dc34b5d7a py3: convert kwargs keys' back to bytes using pycompat.byteskwargs()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32992
diff changeset
  1551
        mapping = pycompat.byteskwargs(mapping)
8361
d8c5a7f25a40 templater: make the templating engine pluggable to some extent
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8360
diff changeset
  1552
        ttype = t in self.map and self.map[t][0] or 'default'
13187
e3b87fb34d00 templater: clarify engine caching
Matt Mackall <mpm@selenic.com>
parents: 13176
diff changeset
  1553
        if ttype not in self.ecache:
28831
6b86ce3e3576 templater: give better error message for invalid engine type
Yuya Nishihara <yuya@tcha.org>
parents: 28696
diff changeset
  1554
            try:
6b86ce3e3576 templater: give better error message for invalid engine type
Yuya Nishihara <yuya@tcha.org>
parents: 28696
diff changeset
  1555
                ecls = engines[ttype]
6b86ce3e3576 templater: give better error message for invalid engine type
Yuya Nishihara <yuya@tcha.org>
parents: 28696
diff changeset
  1556
            except KeyError:
6b86ce3e3576 templater: give better error message for invalid engine type
Yuya Nishihara <yuya@tcha.org>
parents: 28696
diff changeset
  1557
                raise error.Abort(_('invalid template engine: %s') % ttype)
28957
d813132ea361 templater: load and expand aliases by template engine (API) (issue4842)
Yuya Nishihara <yuya@tcha.org>
parents: 28956
diff changeset
  1558
            self.ecache[ttype] = ecls(self.load, self.filters, self.defaults,
35472
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35471
diff changeset
  1559
                                      self._resources, self._aliases)
13187
e3b87fb34d00 templater: clarify engine caching
Matt Mackall <mpm@selenic.com>
parents: 13176
diff changeset
  1560
        proc = self.ecache[ttype]
8361
d8c5a7f25a40 templater: make the templating engine pluggable to some extent
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8360
diff changeset
  1561
10847
90f4367535a5 templater: map -> mapping
Matt Mackall <mpm@selenic.com>
parents: 10846
diff changeset
  1562
        stream = proc.process(t, mapping)
7396
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7107
diff changeset
  1563
        if self.minchunk:
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7107
diff changeset
  1564
            stream = util.increasingchunks(stream, min=self.minchunk,
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7107
diff changeset
  1565
                                           max=self.maxchunk)
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7107
diff changeset
  1566
        return stream
7434
cf7741aa1e96 kill some trailing spaces
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7396
diff changeset
  1567
22634
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1568
def templatepaths():
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1569
    '''return locations used for template files.'''
22636
d844e220792a templater: don't search randomly for templates - trust util.datapath
Mads Kiilerich <madski@unity3d.com>
parents: 22635
diff changeset
  1570
    pathsrel = ['templates']
22635
660861a6fad4 templater: inline global 'path' list in templatepaths
Mads Kiilerich <madski@unity3d.com>
parents: 22634
diff changeset
  1571
    paths = [os.path.normpath(os.path.join(util.datapath, f))
660861a6fad4 templater: inline global 'path' list in templatepaths
Mads Kiilerich <madski@unity3d.com>
parents: 22634
diff changeset
  1572
             for f in pathsrel]
660861a6fad4 templater: inline global 'path' list in templatepaths
Mads Kiilerich <madski@unity3d.com>
parents: 22634
diff changeset
  1573
    return [p for p in paths if os.path.isdir(p)]
2189
e3eba577a0ae move changeset_templater into templater module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2001
diff changeset
  1574
22634
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1575
def templatepath(name):
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1576
    '''return location of template file. returns None if not found.'''
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1577
    for p in templatepaths():
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1578
        f = os.path.join(p, name)
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1579
        if os.path.exists(f):
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1580
            return f
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1581
    return None
2189
e3eba577a0ae move changeset_templater into templater module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2001
diff changeset
  1582
9842
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1583
def stylemap(styles, paths=None):
7966
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1584
    """Return path to mapfile for a given style.
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1585
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1586
    Searches mapfile in the following locations:
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1587
    1. templatepath/style/map
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1588
    2. templatepath/map-style
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1589
    3. templatepath/map
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1590
    """
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1591
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1592
    if paths is None:
22634
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
  1593
        paths = templatepaths()
36579
7f6be7121b28 py3: replace type 'str' by 'bytes' in templater.py
Yuya Nishihara <yuya@tcha.org>
parents: 36575
diff changeset
  1594
    elif isinstance(paths, bytes):
8223
02145b700fe4 templater: fix little problem from stylemap() changes
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8218
diff changeset
  1595
        paths = [paths]
7966
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1596
36579
7f6be7121b28 py3: replace type 'str' by 'bytes' in templater.py
Yuya Nishihara <yuya@tcha.org>
parents: 36575
diff changeset
  1597
    if isinstance(styles, bytes):
9842
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1598
        styles = [styles]
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1599
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1600
    for style in styles:
24296
b73a22d1d9bf hgweb: prevent loading style map from directories other than specified paths
Yuya Nishihara <yuya@tcha.org>
parents: 23167
diff changeset
  1601
        # only plain name is allowed to honor template paths
b73a22d1d9bf hgweb: prevent loading style map from directories other than specified paths
Yuya Nishihara <yuya@tcha.org>
parents: 23167
diff changeset
  1602
        if (not style
b73a22d1d9bf hgweb: prevent loading style map from directories other than specified paths
Yuya Nishihara <yuya@tcha.org>
parents: 23167
diff changeset
  1603
            or style in (os.curdir, os.pardir)
30620
bb77654dc7ae py3: replace os.sep with pycompat.ossep (part 3 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30342
diff changeset
  1604
            or pycompat.ossep in style
30630
bcf4a975f93d py3: replace os.altsep with pycompat.altsep
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30620
diff changeset
  1605
            or pycompat.osaltsep and pycompat.osaltsep in style):
9842
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1606
            continue
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1607
        locations = [os.path.join(style, 'map'), 'map-' + style]
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1608
        locations.append('map')
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1609
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1610
        for path in paths:
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1611
            for location in locations:
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1612
                mapfile = os.path.join(path, location)
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1613
                if os.path.isfile(mapfile):
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
  1614
                    return style, mapfile
7966
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1615
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
  1616
    raise RuntimeError("No hgweb templates found in %r" % paths)
24601
d80819f67d59 templater: tell hggettext to collect help of template functions
Yuya Nishihara <yuya@tcha.org>
parents: 24586
diff changeset
  1617
28695
cc103bd0dbf9 registrar: add templatefunc to mark a function as template function (API)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28687
diff changeset
  1618
def loadfunction(ui, extname, registrarobj):
cc103bd0dbf9 registrar: add templatefunc to mark a function as template function (API)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28687
diff changeset
  1619
    """Load template function from specified registrarobj
cc103bd0dbf9 registrar: add templatefunc to mark a function as template function (API)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28687
diff changeset
  1620
    """
cc103bd0dbf9 registrar: add templatefunc to mark a function as template function (API)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28687
diff changeset
  1621
    for name, func in registrarobj._table.iteritems():
cc103bd0dbf9 registrar: add templatefunc to mark a function as template function (API)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28687
diff changeset
  1622
        funcs[name] = func
cc103bd0dbf9 registrar: add templatefunc to mark a function as template function (API)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28687
diff changeset
  1623
24601
d80819f67d59 templater: tell hggettext to collect help of template functions
Yuya Nishihara <yuya@tcha.org>
parents: 24586
diff changeset
  1624
# tell hggettext to extract docstrings from these functions:
d80819f67d59 templater: tell hggettext to collect help of template functions
Yuya Nishihara <yuya@tcha.org>
parents: 24586
diff changeset
  1625
i18nfunctions = funcs.values()