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