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