mercurial/templater.py
author Yuya Nishihara <yuya@tcha.org>
Thu, 07 Jun 2018 23:27:54 +0900
changeset 39582 28f974d83c0a
parent 38440 3813c6b7337c
child 40475 8fa26f3baf30
permissions -rw-r--r--
templater: remove unused context argument from most resourcemapper functions While working on demand loading of ctx/fctx objects, I noticed that it's quite easy to create infinite recursion by carelessly using the template context in the resource mapper. Let's make that not happen.
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
37014
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
     8
"""Slightly complicated template engine for commands and hgweb
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
     9
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    10
This module provides low-level interface to the template engine. See the
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    11
formatter and cmdutil modules if you are looking for high-level functions
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    12
such as ``cmdutil.rendertemplate(ctx, tmpl)``.
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    13
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    14
Internal Data Types
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    15
-------------------
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    16
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    17
Template keywords and functions take a dictionary of current symbols and
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    18
resources (a "mapping") and return result. Inputs and outputs must be one
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    19
of the following data types:
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    20
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    21
bytes
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    22
    a byte string, which is generally a human-readable text in local encoding.
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    23
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    24
generator
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    25
    a lazily-evaluated byte string, which is a possibly nested generator of
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    26
    values of any printable types, and  will be folded by ``stringify()``
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    27
    or ``flatten()``.
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    28
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    29
None
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    30
    sometimes represents an empty value, which can be stringified to ''.
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    31
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    32
True, False, int, float
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    33
    can be stringified as such.
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    34
38226
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38225
diff changeset
    35
wrappedbytes, wrappedvalue
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38225
diff changeset
    36
    a wrapper for the above printable types.
7824783a6d5e templater: add wrapped types for pure non-list/dict values
Yuya Nishihara <yuya@tcha.org>
parents: 38225
diff changeset
    37
38285
8d6109b49b31 templater: introduce a wrapper for date tuple (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 38283
diff changeset
    38
date
8d6109b49b31 templater: introduce a wrapper for date tuple (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 38283
diff changeset
    39
    represents a (unixtime, offset) tuple.
37014
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    40
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    41
hybrid
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    42
    represents a list/dict of printable values, which can also be converted
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    43
    to mappings by % operator.
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    44
38283
0e0d03d09ecd templater: rename mappable to hybriditem as it is the primary use case
Yuya Nishihara <yuya@tcha.org>
parents: 38226
diff changeset
    45
hybriditem
37014
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    46
    represents a scalar printable value, also supports % operator.
37399
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37398
diff changeset
    47
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37398
diff changeset
    48
mappinggenerator, mappinglist
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37398
diff changeset
    49
    represents mappings (i.e. a list of dicts), which may have default
0b64416224d9 templater: add class representing a nested mappings
Yuya Nishihara <yuya@tcha.org>
parents: 37398
diff changeset
    50
    output format.
37499
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37399
diff changeset
    51
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37399
diff changeset
    52
mappedgenerator
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37399
diff changeset
    53
    a lazily-evaluated list of byte strings, which is e.g. a result of %
75c13343cf38 templater: wrap result of '%' operation so it never looks like a thunk
Yuya Nishihara <yuya@tcha.org>
parents: 37399
diff changeset
    54
    operation.
37014
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    55
"""
a5311d7f4af8 templater: add brief doc about internal data types
Yuya Nishihara <yuya@tcha.org>
parents: 36989
diff changeset
    56
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
    57
from __future__ import absolute_import, print_function
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    58
37073
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
    59
import abc
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    60
import os
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    61
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    62
from .i18n import _
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    63
from . import (
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    64
    config,
31520
6f150bb19317 templater: make pad() compute actual width
Yuya Nishihara <yuya@tcha.org>
parents: 31519
diff changeset
    65
    encoding,
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    66
    error,
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    67
    parser,
30615
bb77654dc7ae py3: replace os.sep with pycompat.ossep (part 3 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
    68
    pycompat,
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    69
    templatefilters,
36922
521f6c7e1756 templater: split template functions to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36921
diff changeset
    70
    templatefuncs,
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
    71
    templateutil,
25985
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    72
    util,
7eb357b5f774 templater: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25815
diff changeset
    73
)
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37075
diff changeset
    74
from .utils import (
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37075
diff changeset
    75
    stringutil,
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37075
diff changeset
    76
)
36443
8dbd97aef915 templater: move specialized exception types to top
Yuya Nishihara <yuya@tcha.org>
parents: 36245
diff changeset
    77
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    78
# template parsing
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    79
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    80
elements = {
25815
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    81
    # 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
    82
    "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
    83
    ".": (18, None, None, (".", 18), None),
34329
6367318327f0 templater: adjust binding strength of '%' and '|' operators (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 34328
diff changeset
    84
    "%": (15, None, None, ("%", 15), None),
31884
0926ca37a990 templater: adjust binding strengths to make room for key-value operator
Yuya Nishihara <yuya@tcha.org>
parents: 31883
diff changeset
    85
    "|": (15, None, None, ("|", 15), None),
0926ca37a990 templater: adjust binding strengths to make room for key-value operator
Yuya Nishihara <yuya@tcha.org>
parents: 31883
diff changeset
    86
    "*": (5, None, None, ("*", 5), None),
0926ca37a990 templater: adjust binding strengths to make room for key-value operator
Yuya Nishihara <yuya@tcha.org>
parents: 31883
diff changeset
    87
    "/": (5, None, None, ("/", 5), None),
0926ca37a990 templater: adjust binding strengths to make room for key-value operator
Yuya Nishihara <yuya@tcha.org>
parents: 31883
diff changeset
    88
    "+": (4, None, None, ("+", 4), None),
0926ca37a990 templater: adjust binding strengths to make room for key-value operator
Yuya Nishihara <yuya@tcha.org>
parents: 31883
diff changeset
    89
    "-": (4, None, ("negate", 19), ("-", 4), None),
31885
d18b624c1c06 templater: add parsing rule for key-value pair
Yuya Nishihara <yuya@tcha.org>
parents: 31884
diff changeset
    90
    "=": (3, None, None, ("keyvalue", 3), None),
31883
25be03a33f50 templater: sort token table by binding strength
Yuya Nishihara <yuya@tcha.org>
parents: 31880
diff changeset
    91
    ",": (2, None, None, ("list", 2), None),
25be03a33f50 templater: sort token table by binding strength
Yuya Nishihara <yuya@tcha.org>
parents: 31880
diff changeset
    92
    ")": (0, None, None, None, None),
25815
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    93
    "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
    94
    "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
    95
    "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
    96
    "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
    97
    "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
    98
}
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
    99
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   100
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
   101
    """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
   102
    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
   103
    pos = start
32154
52e222eef646 py3: use pycompat.bytestr instead of bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32037
diff changeset
   104
    program = pycompat.bytestr(program)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   105
    while pos < end:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   106
        c = program[pos]
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   107
        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
   108
            pass
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   109
        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
   110
            yield (c, None, pos)
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   111
        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
   112
            s = pos + 1
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   113
            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
   114
            yield ('template', data, s)
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   115
            pos -= 1
25784
33e613687dab templater: remove processing of "string" literals from tokenizer
Yuya Nishihara <yuya@tcha.org>
parents: 25783
diff changeset
   116
        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
   117
            # handle quoted strings
33e613687dab templater: remove processing of "string" literals from tokenizer
Yuya Nishihara <yuya@tcha.org>
parents: 25783
diff changeset
   118
            c = program[pos + 1]
33e613687dab templater: remove processing of "string" literals from tokenizer
Yuya Nishihara <yuya@tcha.org>
parents: 25783
diff changeset
   119
            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
   120
            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
   121
                d = program[pos]
25638
6047b60cdd09 templater: fix handling of \-escapes in raw string literals
Yuya Nishihara <yuya@tcha.org>
parents: 25637
diff changeset
   122
                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
   123
                    pos += 2
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   124
                    continue
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   125
                if d == c:
25785
f976b7dc5e7b templater: unify "string" and "rawstring"
Yuya Nishihara <yuya@tcha.org>
parents: 25784
diff changeset
   126
                    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
   127
                    break
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   128
                pos += 1
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   129
            else:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   130
                raise error.ParseError(_("unterminated string"), s)
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   131
        elif c.isdigit():
25002
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   132
            s = pos
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   133
            while pos < end:
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   134
                d = program[pos]
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   135
                if not d.isdigit():
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   136
                    break
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   137
                pos += 1
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   138
            yield ('integer', program[s:pos], s)
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   139
            pos -= 1
36546
14bbb54a9c5b py3: fix type of string literals in templater.tokenize()
Yuya Nishihara <yuya@tcha.org>
parents: 36545
diff changeset
   140
        elif (c == '\\' and program[pos:pos + 2] in (br"\'", br'\"')
14bbb54a9c5b py3: fix type of string literals in templater.tokenize()
Yuya Nishihara <yuya@tcha.org>
parents: 36545
diff changeset
   141
              or c == 'r' and program[pos:pos + 3] in (br"r\'", br'r\"')):
25676
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   142
            # 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
   143
            # 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
   144
            # 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
   145
            #
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   146
            # 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
   147
            # 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
   148
            # ------------------------    ------------    ------------------
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   149
            # {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
   150
            #             ~~~~~~~~
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   151
            #             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
   152
            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
   153
                pos += 1
25785
f976b7dc5e7b templater: unify "string" and "rawstring"
Yuya Nishihara <yuya@tcha.org>
parents: 25784
diff changeset
   154
                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
   155
            else:
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   156
                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
   157
            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
   158
            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
   159
            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
   160
                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
   161
                    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
   162
                    continue
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   163
                if program.startswith(quote, pos, end):
26215
72aad184f061 templater: create string unescape helper (issue4798)
Matt Mackall <mpm@selenic.com>
parents: 26197
diff changeset
   164
                    # 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
   165
                    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
   166
                    if token == 'template':
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   167
                        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
   168
                    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
   169
                    pos += 1
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   170
                    break
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   171
                pos += 1
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   172
            else:
ec9c258e666d templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
Yuya Nishihara <yuya@tcha.org>
parents: 25638
diff changeset
   173
                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
   174
        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
   175
            s = pos
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   176
            pos += 1
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   177
            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
   178
                d = program[pos]
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   179
                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
   180
                    break
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   181
                pos += 1
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   182
            sym = program[s:pos]
18893
74ea61318ea8 templater: back out 0615b22da148, it breaks schemes ({1})
Brendan Cully <brendan@kublai.com>
parents: 18889
diff changeset
   183
            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
   184
            pos -= 1
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   185
        elif c == term:
36691
1b179d151578 templater: fix position of terminator character in error message
Yuya Nishihara <yuya@tcha.org>
parents: 36670
diff changeset
   186
            yield ('end', None, pos)
25782
babd2c93bd99 templater: check existence of closing brace of template string
Yuya Nishihara <yuya@tcha.org>
parents: 25781
diff changeset
   187
            return
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   188
        else:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   189
            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
   190
        pos += 1
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   191
    if term:
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   192
        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
   193
    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
   194
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   195
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
   196
    r"""
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   197
    >>> _parsetemplate(b'foo{bar}"baz', 0, 12)
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   198
    ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   199
    >>> _parsetemplate(b'foo{bar}"baz', 0, 12, quote=b'"')
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   200
    ([('string', 'foo'), ('symbol', 'bar')], 9)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   201
    >>> _parsetemplate(b'foo"{bar}', 0, 9, quote=b'"')
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   202
    ([('string', 'foo')], 4)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   203
    >>> _parsetemplate(br'foo\"bar"baz', 0, 12, quote=b'"')
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   204
    ([('string', 'foo"'), ('string', 'bar')], 9)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   205
    >>> _parsetemplate(br'foo\\"bar', 0, 10, quote=b'"')
25785
f976b7dc5e7b templater: unify "string" and "rawstring"
Yuya Nishihara <yuya@tcha.org>
parents: 25784
diff changeset
   206
    ([('string', 'foo\\')], 6)
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   207
    """
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   208
    parsed = []
36244
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   209
    for typ, val, pos in _scantemplate(tmpl, start, stop, quote):
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   210
        if typ == 'string':
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   211
            parsed.append((typ, val))
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   212
        elif typ == 'template':
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   213
            parsed.append(val)
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   214
        elif typ == 'end':
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   215
            return parsed, pos
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   216
        else:
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   217
            raise error.ProgrammingError('unexpected type: %s' % typ)
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   218
    raise error.ProgrammingError('unterminated scanning of template')
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   219
36509
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   220
def scantemplate(tmpl, raw=False):
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   221
    r"""Scan (type, start, end) positions of outermost elements in template
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   222
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   223
    If raw=True, a backslash is not taken as an escape character just like
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   224
    r'' string in Python. Note that this is different from r'' literal in
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   225
    template in that no template fragment can appear in r'', e.g. r'{foo}'
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   226
    is a literal '{foo}', but ('{foo}', raw=True) is a template expression
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   227
    'foo'.
36245
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   228
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   229
    >>> list(scantemplate(b'foo{bar}"baz'))
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   230
    [('string', 0, 3), ('template', 3, 8), ('string', 8, 12)]
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   231
    >>> list(scantemplate(b'outer{"inner"}outer'))
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   232
    [('string', 0, 5), ('template', 5, 14), ('string', 14, 19)]
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   233
    >>> list(scantemplate(b'foo\\{escaped}'))
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   234
    [('string', 0, 5), ('string', 5, 13)]
36509
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   235
    >>> list(scantemplate(b'foo\\{escaped}', raw=True))
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   236
    [('string', 0, 4), ('template', 4, 13)]
36245
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   237
    """
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   238
    last = None
36509
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   239
    for typ, val, pos in _scantemplate(tmpl, 0, len(tmpl), raw=raw):
36245
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   240
        if last:
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   241
            yield last + (pos,)
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   242
        if typ == 'end':
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   243
            return
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   244
        else:
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   245
            last = (typ, pos)
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   246
    raise error.ProgrammingError('unterminated scanning of template')
c6ce479f7a28 templater: add function to help substituting patterns in template string
Yuya Nishihara <yuya@tcha.org>
parents: 36244
diff changeset
   247
36509
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   248
def _scantemplate(tmpl, start, stop, quote='', raw=False):
36244
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   249
    """Parse template string into chunks of strings and template expressions"""
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   250
    sepchars = '{' + quote
36509
638c012a87ef templater: add option to parse template string just like raw string literal
Yuya Nishihara <yuya@tcha.org>
parents: 36500
diff changeset
   251
    unescape = [parser.unescapestr, pycompat.identity][raw]
25781
82c918509ef5 templater: extract function that parses template string
Yuya Nishihara <yuya@tcha.org>
parents: 25780
diff changeset
   252
    pos = start
25654
af329a84310c parser: accept iterator of tokens instead of tokenizer function and program
Yuya Nishihara <yuya@tcha.org>
parents: 25599
diff changeset
   253
    p = parser.parser(elements)
36669
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   254
    try:
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   255
        while pos < stop:
38085
e887381e2976 py3: bytestr() bytes to get bytechar while iterating on it
Pulkit Goyal <7895pulkit@gmail.com>
parents: 37501
diff changeset
   256
            n = min((tmpl.find(c, pos, stop)
e887381e2976 py3: bytestr() bytes to get bytechar while iterating on it
Pulkit Goyal <7895pulkit@gmail.com>
parents: 37501
diff changeset
   257
                     for c in pycompat.bytestr(sepchars)),
36669
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   258
                    key=lambda n: (n < 0, n))
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   259
            if n < 0:
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   260
                yield ('string', unescape(tmpl[pos:stop]), pos)
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   261
                pos = stop
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   262
                break
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   263
            c = tmpl[n:n + 1]
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   264
            bs = 0  # count leading backslashes
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   265
            if not raw:
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   266
                bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   267
            if bs % 2 == 1:
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   268
                # escaped (e.g. '\{', '\\\{', but not '\\{')
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   269
                yield ('string', unescape(tmpl[pos:n - 1]) + c, pos)
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   270
                pos = n + 1
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   271
                continue
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   272
            if n > pos:
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   273
                yield ('string', unescape(tmpl[pos:n]), pos)
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   274
            if c == quote:
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   275
                yield ('end', None, n + 1)
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   276
                return
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   277
36669
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   278
            parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
36691
1b179d151578 templater: fix position of terminator character in error message
Yuya Nishihara <yuya@tcha.org>
parents: 36670
diff changeset
   279
            if not tmpl.startswith('}', pos):
36669
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   280
                raise error.ParseError(_("invalid token"), pos)
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   281
            yield ('template', parseres, n)
36691
1b179d151578 templater: fix position of terminator character in error message
Yuya Nishihara <yuya@tcha.org>
parents: 36670
diff changeset
   282
            pos += 1
25783
1f6878c87c25 templater: introduce one-pass parsing of nested template strings
Yuya Nishihara <yuya@tcha.org>
parents: 25782
diff changeset
   283
36669
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   284
        if quote:
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   285
            raise error.ParseError(_("unterminated string"), start)
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   286
    except error.ParseError as inst:
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   287
        if len(inst.args) > 1:  # has location
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   288
            loc = inst.args[1]
36670
44048f1bcee5 templater: provide hint for multi-line templates with parse errors
Ryan McElroy <rmcelroy@fb.com>
parents: 36669
diff changeset
   289
            # Offset the caret location by the number of newlines before the
44048f1bcee5 templater: provide hint for multi-line templates with parse errors
Ryan McElroy <rmcelroy@fb.com>
parents: 36669
diff changeset
   290
            # location of the error, since we will replace one-char newlines
44048f1bcee5 templater: provide hint for multi-line templates with parse errors
Ryan McElroy <rmcelroy@fb.com>
parents: 36669
diff changeset
   291
            # with the two-char literal r'\n'.
44048f1bcee5 templater: provide hint for multi-line templates with parse errors
Ryan McElroy <rmcelroy@fb.com>
parents: 36669
diff changeset
   292
            offset = tmpl[:loc].count('\n')
44048f1bcee5 templater: provide hint for multi-line templates with parse errors
Ryan McElroy <rmcelroy@fb.com>
parents: 36669
diff changeset
   293
            tmpl = tmpl.replace('\n', br'\n')
44048f1bcee5 templater: provide hint for multi-line templates with parse errors
Ryan McElroy <rmcelroy@fb.com>
parents: 36669
diff changeset
   294
            # We want the caret to point to the place in the template that
44048f1bcee5 templater: provide hint for multi-line templates with parse errors
Ryan McElroy <rmcelroy@fb.com>
parents: 36669
diff changeset
   295
            # failed to parse, but in a hint we get a open paren at the
36691
1b179d151578 templater: fix position of terminator character in error message
Yuya Nishihara <yuya@tcha.org>
parents: 36670
diff changeset
   296
            # start. Therefore, we print "loc + 1" spaces (instead of "loc")
36670
44048f1bcee5 templater: provide hint for multi-line templates with parse errors
Ryan McElroy <rmcelroy@fb.com>
parents: 36669
diff changeset
   297
            # to line up the caret with the location of the error.
36691
1b179d151578 templater: fix position of terminator character in error message
Yuya Nishihara <yuya@tcha.org>
parents: 36670
diff changeset
   298
            inst.hint = (tmpl + '\n'
1b179d151578 templater: fix position of terminator character in error message
Yuya Nishihara <yuya@tcha.org>
parents: 36670
diff changeset
   299
                         + ' ' * (loc + 1 + offset) + '^ ' + _('here'))
36669
80d7fb6c2dec templater: add hint to template parse errors to help locate issues
Ryan McElroy <rmcelroy@fb.com>
parents: 36648
diff changeset
   300
        raise
36244
18bdfad8506e templater: extract function scanning template string
Yuya Nishihara <yuya@tcha.org>
parents: 35744
diff changeset
   301
    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
   302
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   303
def _unnesttemplatelist(tree):
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   304
    """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
   305
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   306
    >>> def f(tree):
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   307
    ...     print(pycompat.sysstr(prettyformat(_unnesttemplatelist(tree))))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   308
    >>> f((b'template', []))
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34071
diff changeset
   309
    (string '')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   310
    >>> f((b'template', [(b'string', b'foo')]))
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34071
diff changeset
   311
    (string 'foo')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   312
    >>> f((b'template', [(b'string', b'foo'), (b'symbol', b'rev')]))
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   313
    (template
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34071
diff changeset
   314
      (string 'foo')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34071
diff changeset
   315
      (symbol 'rev'))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   316
    >>> f((b'template', [(b'symbol', b'rev')]))  # template(rev) -> str
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   317
    (template
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34071
diff changeset
   318
      (symbol 'rev'))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   319
    >>> f((b'template', [(b'template', [(b'string', b'foo')])]))
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34071
diff changeset
   320
    (string 'foo')
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   321
    """
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   322
    if not isinstance(tree, tuple):
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   323
        return tree
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   324
    op = tree[0]
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   325
    if op != 'template':
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   326
        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
   327
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   328
    assert len(tree) == 2
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   329
    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
   330
    if not xs:
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   331
        return ('string', '')  # empty template ""
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   332
    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
   333
        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
   334
    else:
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   335
        return (op,) + xs
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   336
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   337
def parse(tmpl):
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   338
    """Parse template string into tree"""
25781
82c918509ef5 templater: extract function that parses template string
Yuya Nishihara <yuya@tcha.org>
parents: 25780
diff changeset
   339
    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
   340
    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
   341
    return _unnesttemplatelist(('template', parsed))
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   342
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   343
def _parseexpr(expr):
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   344
    """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
   345
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   346
    >>> _parseexpr(b'"foo"')
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   347
    ('string', 'foo')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   348
    >>> _parseexpr(b'foo(bar)')
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   349
    ('func', ('symbol', 'foo'), ('symbol', 'bar'))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   350
    >>> _parseexpr(b'foo(')
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   351
    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
   352
      ...
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   353
    ParseError: ('not a prefix: end', 4)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   354
    >>> _parseexpr(b'"foo" "bar"')
28911
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   355
    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
   356
      ...
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   357
    ParseError: ('invalid token', 7)
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   358
    """
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   359
    p = parser.parser(elements)
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   360
    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
   361
    if pos != len(expr):
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   362
        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
   363
    return _unnesttemplatelist(tree)
35da19348143 templater: add function to parse whole string as template expression
Yuya Nishihara <yuya@tcha.org>
parents: 28837
diff changeset
   364
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   365
def prettyformat(tree):
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   366
    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
   367
25001
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
   368
def compileexp(exp, context, curmethods):
28956
eea98190ed73 templater: inline compiletemplate() function into engine
Yuya Nishihara <yuya@tcha.org>
parents: 28954
diff changeset
   369
    """Compile parsed template tree to (func, data) pair"""
35744
8685192a8733 templater: fix crash by empty group expression
Yuya Nishihara <yuya@tcha.org>
parents: 35680
diff changeset
   370
    if not exp:
8685192a8733 templater: fix crash by empty group expression
Yuya Nishihara <yuya@tcha.org>
parents: 35680
diff changeset
   371
        raise error.ParseError(_("missing argument"))
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   372
    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
   373
    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
   374
        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
   375
    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
   376
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   377
# template evaluation
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   378
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   379
def getsymbol(exp):
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   380
    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
   381
        return exp[1]
21822
028a48105191 templater: add symbol to error
Ryan McElroy <rmcelroy@fb.com>
parents: 21821
diff changeset
   382
    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
   383
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   384
def getlist(x):
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   385
    if not x:
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   386
        return []
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   387
    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
   388
        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
   389
    return [x]
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   390
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   391
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
   392
    """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
   393
    returns (func, data) pair"""
28546
1987ed32efca templater: relax type of mapped template
Yuya Nishihara <yuya@tcha.org>
parents: 28545
diff changeset
   394
    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
   395
        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
   396
    if exp[0] == 'symbol':
25599
695b93a79d17 templater: comment that gettemplate() has different name resolution order
Yuya Nishihara <yuya@tcha.org>
parents: 25598
diff changeset
   397
        # 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
   398
        # 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
   399
        # 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
   400
        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
   401
    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
   402
27940
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
   403
def _runrecursivesymbol(context, mapping, key):
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
   404
    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
   405
25596
c1975809a6b5 templater: take any string literals as template, but not for rawstring (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25595
diff changeset
   406
def buildtemplate(exp, context):
28547
73d01cba5810 templater: expand list of parsed templates to template node
Yuya Nishihara <yuya@tcha.org>
parents: 28546
diff changeset
   407
    ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   408
    return (templateutil.runtemplate, ctmpl)
25595
a7dd6692e5cb templater: move runtemplate function out of buildmap/runmap pair
Yuya Nishihara <yuya@tcha.org>
parents: 25580
diff changeset
   409
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   410
def buildfilter(exp, context):
26104
0f1bc7faa50d templater: inline getfilter() to buildfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 25985
diff changeset
   411
    n = getsymbol(exp[2])
0f1bc7faa50d templater: inline getfilter() to buildfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 25985
diff changeset
   412
    if n in context._filters:
0f1bc7faa50d templater: inline getfilter() to buildfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 25985
diff changeset
   413
        filt = context._filters[n]
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   414
        arg = compileexp(exp[1], context, methods)
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   415
        return (templateutil.runfilter, (arg, filt))
36912
543afbdc8e59 templater: move function table to the "context" object
Yuya Nishihara <yuya@tcha.org>
parents: 36712
diff changeset
   416
    if n in context._funcs:
543afbdc8e59 templater: move function table to the "context" object
Yuya Nishihara <yuya@tcha.org>
parents: 36712
diff changeset
   417
        f = context._funcs[n]
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   418
        args = _buildfuncargs(exp[1], context, methods, n, f._argspec)
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   419
        return (f, args)
26104
0f1bc7faa50d templater: inline getfilter() to buildfilter()
Yuya Nishihara <yuya@tcha.org>
parents: 25985
diff changeset
   420
    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
   421
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   422
def buildmap(exp, context):
34325
86d050abd5c1 templater: do not destructure operands in buildmap()
Yuya Nishihara <yuya@tcha.org>
parents: 34324
diff changeset
   423
    darg = compileexp(exp[1], context, methods)
86d050abd5c1 templater: do not destructure operands in buildmap()
Yuya Nishihara <yuya@tcha.org>
parents: 34324
diff changeset
   424
    targ = gettemplate(exp[2], context)
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   425
    return (templateutil.runmap, (darg, targ))
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   426
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   427
def buildmember(exp, context):
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   428
    darg = compileexp(exp[1], context, methods)
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   429
    memb = getsymbol(exp[2])
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   430
    return (templateutil.runmember, (darg, memb))
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   431
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   432
def buildnegate(exp, context):
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   433
    arg = compileexp(exp[1], context, exprmethods)
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   434
    return (templateutil.runnegate, arg)
30115
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)
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   439
    return (templateutil.runarithmetic, (func, left, right))
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   440
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   441
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
   442
    n = getsymbol(exp[1])
36912
543afbdc8e59 templater: move function table to the "context" object
Yuya Nishihara <yuya@tcha.org>
parents: 36712
diff changeset
   443
    if n in context._funcs:
543afbdc8e59 templater: move function table to the "context" object
Yuya Nishihara <yuya@tcha.org>
parents: 36712
diff changeset
   444
        f = context._funcs[n]
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   445
        args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec)
14925
ab545a15d807 templater: use a global funcs table
Matt Mackall <mpm@selenic.com>
parents: 14168
diff changeset
   446
        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
   447
    if n in context._filters:
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   448
        args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None)
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   449
        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
   450
            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
   451
        f = context._filters[n]
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   452
        return (templateutil.runfilter, (args[0], f))
20857
6eb55310fcbc templater: raise error for unknown func
Sean Farley <sean.michael.farley@gmail.com>
parents: 20663
diff changeset
   453
    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
   454
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   455
def _buildfuncargs(exp, context, curmethods, funcname, argspec):
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   456
    """Compile parsed tree of function arguments into list or dict of
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   457
    (func, data) pairs
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   458
36987
4b744c7b35ce templater: fix invalid reference of runsymbol in doctest
Yuya Nishihara <yuya@tcha.org>
parents: 36983
diff changeset
   459
    >>> context = engine(lambda t: (templateutil.runsymbol, t))
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   460
    >>> def fargs(expr, argspec):
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   461
    ...     x = _parseexpr(expr)
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   462
    ...     n = getsymbol(x[1])
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   463
    ...     return _buildfuncargs(x[2], context, exprmethods, n, argspec)
34139
be00af4a1ac5 doctest: coerce dict.keys() to list
Yuya Nishihara <yuya@tcha.org>
parents: 34137
diff changeset
   464
    >>> list(fargs(b'a(l=1, k=2)', b'k l m').keys())
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   465
    ['l', 'k']
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   466
    >>> args = fargs(b'a(opts=1, k=2)', b'**opts')
34139
be00af4a1ac5 doctest: coerce dict.keys() to list
Yuya Nishihara <yuya@tcha.org>
parents: 34137
diff changeset
   467
    >>> list(args.keys()), list(args[b'opts'].keys())
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   468
    (['opts'], ['opts', 'k'])
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   469
    """
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   470
    def compiledict(xs):
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   471
        return util.sortdict((k, compileexp(x, context, curmethods))
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   472
                             for k, x in xs.iteritems())
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   473
    def compilelist(xs):
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   474
        return [compileexp(x, context, curmethods) for x in xs]
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   475
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   476
    if not argspec:
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   477
        # filter or function with no argspec: return list of positional args
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   478
        return compilelist(getlist(exp))
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   479
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   480
    # function with argspec: return dict of named args
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   481
    _poskeys, varkey, _keys, optkey = argspec = parser.splitargspec(argspec)
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   482
    treeargs = parser.buildargsdict(getlist(exp), funcname, argspec,
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   483
                                    keyvaluenode='keyvalue', keynode='symbol')
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   484
    compargs = util.sortdict()
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   485
    if varkey:
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   486
        compargs[varkey] = compilelist(treeargs.pop(varkey))
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   487
    if optkey:
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31887
diff changeset
   488
        compargs[optkey] = compiledict(treeargs.pop(optkey))
31886
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   489
    compargs.update(compiledict(treeargs))
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   490
    return compargs
bdda942f4b9c templater: add support for keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31885
diff changeset
   491
31885
d18b624c1c06 templater: add parsing rule for key-value pair
Yuya Nishihara <yuya@tcha.org>
parents: 31884
diff changeset
   492
def buildkeyvaluepair(exp, content):
d18b624c1c06 templater: add parsing rule for key-value pair
Yuya Nishihara <yuya@tcha.org>
parents: 31884
diff changeset
   493
    raise error.ParseError(_("can't use a key-value pair in this context"))
d18b624c1c06 templater: add parsing rule for key-value pair
Yuya Nishihara <yuya@tcha.org>
parents: 31884
diff changeset
   494
25001
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
   495
# 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
   496
exprmethods = {
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   497
    "integer": lambda e, c: (templateutil.runinteger, e[1]),
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   498
    "string": lambda e, c: (templateutil.runstring, e[1]),
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   499
    "symbol": lambda e, c: (templateutil.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
   500
    "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
   501
    "group": lambda e, c: compileexp(e[1], c, exprmethods),
34535
78590585c0db templater: add dot operator to easily access a sub item
Yuya Nishihara <yuya@tcha.org>
parents: 34534
diff changeset
   502
    ".": buildmember,
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   503
    "|": buildfilter,
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   504
    "%": buildmap,
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   505
    "func": buildfunc,
31885
d18b624c1c06 templater: add parsing rule for key-value pair
Yuya Nishihara <yuya@tcha.org>
parents: 31884
diff changeset
   506
    "keyvalue": buildkeyvaluepair,
30115
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   507
    "+": 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
   508
    "-": 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
   509
    "negate": buildnegate,
8e42dfde93d1 templater: provide arithmetic operations on integers
Simon Farnsworth <simonfar@fb.com>
parents: 30083
diff changeset
   510
    "*": 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
   511
    "/": 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
   512
    }
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   513
25001
9668c1a433b3 templater: switch methods table on compileexp() of func args and inner expr
Yuya Nishihara <yuya@tcha.org>
parents: 24988
diff changeset
   514
# 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
   515
methods = exprmethods.copy()
25002
829faf8ab605 templater: tokenize decimal integer literal (issue4638) (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 25001
diff changeset
   516
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
   517
28912
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   518
class _aliasrules(parser.basealiasrules):
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   519
    """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
   520
    _section = _('template alias')
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   521
    _parse = staticmethod(_parseexpr)
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   522
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   523
    @staticmethod
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   524
    def _trygetfunc(tree):
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   525
        """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
   526
        None"""
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   527
        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
   528
            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
   529
        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
   530
            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
   531
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   532
def expandaliases(tree, aliases):
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   533
    """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
   534
    aliasmap = _aliasrules.buildmap(aliases)
867d6ba2353d templater: add parsing and expansion rules to process "templatealias" section
Yuya Nishihara <yuya@tcha.org>
parents: 28911
diff changeset
   535
    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
   536
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   537
# template engine
1901
c64bef3d7043 use safer string parser for template engine.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1900
diff changeset
   538
24988
e8ff0b09acac templater: rename parsestring() to unquotestring() (API)
Yuya Nishihara <yuya@tcha.org>
parents: 24987
diff changeset
   539
def unquotestring(s):
28630
bf35644b9f3a templater: relax unquotestring() to fall back to bare string
Yuya Nishihara <yuya@tcha.org>
parents: 28628
diff changeset
   540
    '''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
   541
    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
   542
        return s
25696
c1cac25ad1a6 templater: remove workaround for escaped quoted string in quoted template
Yuya Nishihara <yuya@tcha.org>
parents: 25695
diff changeset
   543
    return s[1:-1]
1896
f8f818a04f5b move hgweb template code out to templater
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
   544
37073
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   545
class resourcemapper(object):
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   546
    """Mapper of internal template resources"""
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   547
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   548
    __metaclass__ = abc.ABCMeta
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   549
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   550
    @abc.abstractmethod
39582
28f974d83c0a templater: remove unused context argument from most resourcemapper functions
Yuya Nishihara <yuya@tcha.org>
parents: 38440
diff changeset
   551
    def availablekeys(self, mapping):
37075
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   552
        """Return a set of available resource keys based on the given mapping"""
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   553
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   554
    @abc.abstractmethod
37073
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   555
    def knownkeys(self):
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   556
        """Return a set of supported resource keys"""
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   557
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   558
    @abc.abstractmethod
39582
28f974d83c0a templater: remove unused context argument from most resourcemapper functions
Yuya Nishihara <yuya@tcha.org>
parents: 38440
diff changeset
   559
    def lookup(self, mapping, key):
37073
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   560
        """Return a resource for the key if available; otherwise None"""
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   561
37102
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   562
    @abc.abstractmethod
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   563
    def populatemap(self, context, origmapping, newmapping):
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   564
        """Return a dict of additional mapping items which should be paired
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   565
        with the given new mapping"""
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   566
37073
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   567
class nullresourcemapper(resourcemapper):
39582
28f974d83c0a templater: remove unused context argument from most resourcemapper functions
Yuya Nishihara <yuya@tcha.org>
parents: 38440
diff changeset
   568
    def availablekeys(self, mapping):
37075
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   569
        return set()
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   570
37073
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   571
    def knownkeys(self):
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   572
        return set()
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   573
39582
28f974d83c0a templater: remove unused context argument from most resourcemapper functions
Yuya Nishihara <yuya@tcha.org>
parents: 38440
diff changeset
   574
    def lookup(self, mapping, key):
37073
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   575
        return None
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   576
37102
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   577
    def populatemap(self, context, origmapping, newmapping):
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   578
        return {}
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   579
8218
e61cb2813d2a templater: separate template management and actual string processing
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
   580
class engine(object):
1909
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   581
    '''template expansion engine.
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   582
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   583
    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
   584
    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
   585
    is treated as name of template file.
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   586
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   587
    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
   588
    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
   589
    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
   590
    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
   591
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   592
    expansion also allows formatting and filtering.
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   593
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   594
    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
   595
    {key%format}.
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   596
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   597
    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
   598
    {key|filter1|filter2|...}.'''
37b9f80a5fbb add doc comments to template code.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1906
diff changeset
   599
38354
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   600
    def __init__(self, loader, filters=None, defaults=None, resources=None):
10848
01346cea5485 templater: privatize class variables
Matt Mackall <mpm@selenic.com>
parents: 10847
diff changeset
   601
        self._loader = loader
26330
ec4f3755d997 templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26234
diff changeset
   602
        if filters is None:
ec4f3755d997 templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26234
diff changeset
   603
            filters = {}
10848
01346cea5485 templater: privatize class variables
Matt Mackall <mpm@selenic.com>
parents: 10847
diff changeset
   604
        self._filters = filters
36922
521f6c7e1756 templater: split template functions to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36921
diff changeset
   605
        self._funcs = templatefuncs.funcs  # make this a parameter if needed
26331
2c6a741bf05e templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26330
diff changeset
   606
        if defaults is None:
2c6a741bf05e templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26330
diff changeset
   607
            defaults = {}
35468
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35467
diff changeset
   608
        if resources is None:
37073
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   609
            resources = nullresourcemapper()
10848
01346cea5485 templater: privatize class variables
Matt Mackall <mpm@selenic.com>
parents: 10847
diff changeset
   610
        self._defaults = defaults
35468
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35467
diff changeset
   611
        self._resources = resources
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   612
        self._cache = {}  # key: (func, data)
37398
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   613
        self._tmplcache = {}  # literal template: (func, data)
8218
e61cb2813d2a templater: separate template management and actual string processing
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
   614
37074
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   615
    def overlaymap(self, origmapping, newmapping):
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   616
        """Create combined mapping from the original mapping and partial
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   617
        mapping to override the original"""
37075
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   618
        # do not copy symbols which overrides the defaults depending on
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   619
        # new resources, so the defaults will be re-evaluated (issue5612)
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   620
        knownres = self._resources.knownkeys()
39582
28f974d83c0a templater: remove unused context argument from most resourcemapper functions
Yuya Nishihara <yuya@tcha.org>
parents: 38440
diff changeset
   621
        newres = self._resources.availablekeys(newmapping)
37075
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   622
        mapping = {k: v for k, v in origmapping.iteritems()
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   623
                   if (k in knownres  # not a symbol per self.symbol()
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   624
                       or newres.isdisjoint(self._defaultrequires(k)))}
37074
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   625
        mapping.update(newmapping)
37102
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   626
        mapping.update(
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   627
            self._resources.populatemap(self, origmapping, newmapping))
37074
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   628
        return mapping
2891079fb0c0 templater: factor out function to create mapping dict for nested evaluation
Yuya Nishihara <yuya@tcha.org>
parents: 37073
diff changeset
   629
37075
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   630
    def _defaultrequires(self, key):
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   631
        """Resource keys required by the specified default symbol function"""
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   632
        v = self._defaults.get(key)
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   633
        if v is None or not callable(v):
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   634
            return ()
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   635
        return getattr(v, '_requires', ())
46859b437697 templater: drop symbols which should be overridden by new 'ctx' (issue5612)
Yuya Nishihara <yuya@tcha.org>
parents: 37074
diff changeset
   636
35467
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   637
    def symbol(self, mapping, key):
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   638
        """Resolve symbol to value or function; None if nothing found"""
35470
a33be093ec62 templater: look up symbols/resources as if they were separated (issue5699)
Yuya Nishihara <yuya@tcha.org>
parents: 35468
diff changeset
   639
        v = None
37073
44757e6dad93 templater: introduce resourcemapper class
Yuya Nishihara <yuya@tcha.org>
parents: 37070
diff changeset
   640
        if key not in self._resources.knownkeys():
35470
a33be093ec62 templater: look up symbols/resources as if they were separated (issue5699)
Yuya Nishihara <yuya@tcha.org>
parents: 35468
diff changeset
   641
            v = mapping.get(key)
35467
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   642
        if v is None:
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   643
            v = self._defaults.get(key)
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   644
        return v
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   645
37501
0f4de9c27973 templater: add public interface returning a set of resource keys
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   646
    def availableresourcekeys(self, mapping):
0f4de9c27973 templater: add public interface returning a set of resource keys
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   647
        """Return a set of available resource keys based on the given mapping"""
39582
28f974d83c0a templater: remove unused context argument from most resourcemapper functions
Yuya Nishihara <yuya@tcha.org>
parents: 38440
diff changeset
   648
        return self._resources.availablekeys(mapping)
37501
0f4de9c27973 templater: add public interface returning a set of resource keys
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   649
0f4de9c27973 templater: add public interface returning a set of resource keys
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   650
    def knownresourcekeys(self):
0f4de9c27973 templater: add public interface returning a set of resource keys
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   651
        """Return a set of supported resource keys"""
0f4de9c27973 templater: add public interface returning a set of resource keys
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   652
        return self._resources.knownkeys()
0f4de9c27973 templater: add public interface returning a set of resource keys
Yuya Nishihara <yuya@tcha.org>
parents: 37499
diff changeset
   653
35467
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   654
    def resource(self, mapping, key):
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   655
        """Return internal data (e.g. cache) used for keyword/function
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   656
        evaluation"""
39582
28f974d83c0a templater: remove unused context argument from most resourcemapper functions
Yuya Nishihara <yuya@tcha.org>
parents: 38440
diff changeset
   657
        v = self._resources.lookup(mapping, key)
35468
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35467
diff changeset
   658
        if v is None:
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   659
            raise templateutil.ResourceUnavailable(
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   660
                _('template resource not available: %s') % key)
35468
32c278eb876f templater: keep default resources per template engine (API)
Yuya Nishihara <yuya@tcha.org>
parents: 35467
diff changeset
   661
        return v
35467
d6cfa722b044 templater: look up mapping table through template engine
Yuya Nishihara <yuya@tcha.org>
parents: 35414
diff changeset
   662
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   663
    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
   664
        '''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
   665
        if t not in self._cache:
38354
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   666
            x = self._loader(t)
27940
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
   667
            # 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
   668
            self._cache[t] = (_runrecursivesymbol, t)
27940
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
   669
            try:
28956
eea98190ed73 templater: inline compiletemplate() function into engine
Yuya Nishihara <yuya@tcha.org>
parents: 28954
diff changeset
   670
                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
   671
            except: # re-raises
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
   672
                del self._cache[t]
cfe7da66f555 templater: abort if infinite recursion detected while compiling
Yuya Nishihara <yuya@tcha.org>
parents: 27939
diff changeset
   673
                raise
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 13175
diff changeset
   674
        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
   675
37398
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   676
    def _parse(self, tmpl):
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   677
        """Parse and cache a literal template"""
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   678
        if tmpl not in self._tmplcache:
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   679
            x = parse(tmpl)
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   680
            self._tmplcache[tmpl] = compileexp(x, self, methods)
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   681
        return self._tmplcache[tmpl]
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   682
37067
04aafcec00b9 templater: add context.preload(t) to test if the specified template exists
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   683
    def preload(self, t):
04aafcec00b9 templater: add context.preload(t) to test if the specified template exists
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   684
        """Load, parse, and cache the specified template if available"""
04aafcec00b9 templater: add context.preload(t) to test if the specified template exists
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   685
        try:
04aafcec00b9 templater: add context.preload(t) to test if the specified template exists
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   686
            self._load(t)
04aafcec00b9 templater: add context.preload(t) to test if the specified template exists
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   687
            return True
04aafcec00b9 templater: add context.preload(t) to test if the specified template exists
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   688
        except templateutil.TemplateNotFound:
04aafcec00b9 templater: add context.preload(t) to test if the specified template exists
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   689
            return False
04aafcec00b9 templater: add context.preload(t) to test if the specified template exists
Yuya Nishihara <yuya@tcha.org>
parents: 37019
diff changeset
   690
10853
b6f6d9fd53d6 templater: drop raw method
Matt Mackall <mpm@selenic.com>
parents: 10852
diff changeset
   691
    def process(self, t, mapping):
b6f6d9fd53d6 templater: drop raw method
Matt Mackall <mpm@selenic.com>
parents: 10852
diff changeset
   692
        '''Perform expansion. t is name of map element to expand.
b6f6d9fd53d6 templater: drop raw method
Matt Mackall <mpm@selenic.com>
parents: 10852
diff changeset
   693
        mapping contains added elements for use during expansion. Is a
b6f6d9fd53d6 templater: drop raw method
Matt Mackall <mpm@selenic.com>
parents: 10852
diff changeset
   694
        generator.'''
28545
1d461ee26e1b templater: lift parsed and compiled templates to generic data types
Yuya Nishihara <yuya@tcha.org>
parents: 28462
diff changeset
   695
        func, data = self._load(t)
37398
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   696
        return self._expand(func, data, mapping)
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   697
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   698
    def expand(self, tmpl, mapping):
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   699
        """Perform expansion over a literal template
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   700
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   701
        No user aliases will be expanded since this is supposed to be called
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   702
        with an internal template string.
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   703
        """
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   704
        func, data = self._parse(tmpl)
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   705
        return self._expand(func, data, mapping)
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   706
3235afdfcf1c templater: add function that expands internal literal templates
Yuya Nishihara <yuya@tcha.org>
parents: 37272
diff changeset
   707
    def _expand(self, func, data, mapping):
37102
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   708
        # populate additional items only if they don't exist in the given
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   709
        # mapping. this is slightly different from overlaymap() because the
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   710
        # initial 'revcache' may contain pre-computed items.
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   711
        extramapping = self._resources.populatemap(self, {}, mapping)
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   712
        if extramapping:
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   713
            extramapping.update(mapping)
638a241202a3 templater: add hook point to populate additional mapping items
Yuya Nishihara <yuya@tcha.org>
parents: 37084
diff changeset
   714
            mapping = extramapping
37272
7d3bc1d4e871 templater: pass (context, mapping) down to unwraphybrid()
Yuya Nishihara <yuya@tcha.org>
parents: 37159
diff changeset
   715
        return templateutil.flatten(self, mapping, func(self, mapping, data))
8218
e61cb2813d2a templater: separate template management and actual string processing
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
   716
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
   717
def stylelist():
22634
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   718
    paths = templatepaths()
20312
268a5ab5c27b templater: selecting a style with no templates does not crash (issue4140)
Simon Heimberg <simohe@besonet.ch>
parents: 20067
diff changeset
   719
    if not paths:
268a5ab5c27b templater: selecting a style with no templates does not crash (issue4140)
Simon Heimberg <simohe@besonet.ch>
parents: 20067
diff changeset
   720
        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
   721
    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
   722
    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
   723
    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
   724
        split = file.split(".")
28403
d2e154dddb6e templater: ignore orig/rej files
timeless <timeless@mozdev.org>
parents: 28384
diff changeset
   725
        if split[-1] in ('orig', 'rej'):
d2e154dddb6e templater: ignore orig/rej files
timeless <timeless@mozdev.org>
parents: 28384
diff changeset
   726
            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
   727
        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
   728
            stylelist.append(split[1])
19127
d982edcfe7f0 templater: fix output instability from gsoc patches
Augie Fackler <raf@durin42.com>
parents: 19125
diff changeset
   729
    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
   730
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   731
def _readmapfile(mapfile):
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   732
    """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
   733
    if not os.path.exists(mapfile):
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   734
        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
   735
                          hint=_("available styles: %s") % stylelist())
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   736
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   737
    base = os.path.dirname(mapfile)
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   738
    conf = config.config(includepaths=templatepaths())
34714
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
   739
    conf.read(mapfile, remap={'': 'templates'})
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   740
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   741
    cache = {}
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   742
    tmap = {}
34715
f17a0e18c47e templater: load aliases from [templatealias] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34714
diff changeset
   743
    aliases = []
34712
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   744
34714
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
   745
    val = conf.get('templates', '__base__')
34712
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   746
    if val and val[0] not in "'\"":
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   747
        # treat as a pointer to a base class for this style
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   748
        path = util.normpath(os.path.join(base, val))
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   749
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   750
        # fallback check in template paths
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   751
        if not os.path.exists(path):
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   752
            for p in templatepaths():
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   753
                p2 = util.normpath(os.path.join(p, val))
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   754
                if os.path.isfile(p2):
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   755
                    path = p2
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   756
                    break
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   757
                p3 = util.normpath(os.path.join(p2, "map"))
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   758
                if os.path.isfile(p3):
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   759
                    path = p3
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   760
                    break
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   761
34715
f17a0e18c47e templater: load aliases from [templatealias] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34714
diff changeset
   762
        cache, tmap, aliases = _readmapfile(path)
34712
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   763
34714
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
   764
    for key, val in conf['templates'].items():
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   765
        if not val:
34714
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
   766
            raise error.ParseError(_('missing value'),
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
   767
                                   conf.source('templates', key))
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   768
        if val[0] in "'\"":
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   769
            if val[0] != val[-1]:
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   770
                raise error.ParseError(_('unmatched quotes'),
34714
f4aeb952ab77 templater: load template fragments from [templates] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34712
diff changeset
   771
                                       conf.source('templates', key))
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   772
            cache[key] = unquotestring(val)
34712
56f085334611 templater: simplify merge of __base__ dicts by reading it first
Yuya Nishihara <yuya@tcha.org>
parents: 34693
diff changeset
   773
        elif key != '__base__':
38353
48289eafb37d templater: drop extension point of engine classes (API)
Yuya Nishihara <yuya@tcha.org>
parents: 38352
diff changeset
   774
            tmap[key] = os.path.join(base, val)
34715
f17a0e18c47e templater: load aliases from [templatealias] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34714
diff changeset
   775
    aliases.extend(conf['templatealias'].items())
f17a0e18c47e templater: load aliases from [templatealias] section in map file
Yuya Nishihara <yuya@tcha.org>
parents: 34714
diff changeset
   776
    return cache, tmap, aliases
28953
7f6b8ec691e3 templater: extract function that loads template map file
Yuya Nishihara <yuya@tcha.org>
parents: 28952
diff changeset
   777
38438
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   778
class loader(object):
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   779
    """Load template fragments optionally from a map file"""
35481
964510dcdc2a templater: rewrite docstring of templater.__init__()
Yuya Nishihara <yuya@tcha.org>
parents: 35470
diff changeset
   780
38438
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   781
    def __init__(self, cache, aliases):
26334
0a5a774f5956 templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26333
diff changeset
   782
        if cache is None:
0a5a774f5956 templater: remove a mutable default argument
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 26333
diff changeset
   783
            cache = {}
1975
6e1a8ea5d717 Duplicate cache when creating templater.
Shun-ichi Goto <shunichi.goto@gmail.com>
parents: 1964
diff changeset
   784
        self.cache = cache.copy()
38351
de089e3eb328 templater: mark most attributes as private
Yuya Nishihara <yuya@tcha.org>
parents: 38285
diff changeset
   785
        self._map = {}
38354
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   786
        self._aliasmap = _aliasrules.buildmap(aliases)
1896
f8f818a04f5b move hgweb template code out to templater
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
   787
1899
888d298ddb91 many small changes to templater.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 1897
diff changeset
   788
    def __contains__(self, key):
38351
de089e3eb328 templater: mark most attributes as private
Yuya Nishihara <yuya@tcha.org>
parents: 38285
diff changeset
   789
        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
   790
8218
e61cb2813d2a templater: separate template management and actual string processing
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8198
diff changeset
   791
    def load(self, t):
38354
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   792
        """Get parsed tree 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
   793
        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
   794
            try:
38353
48289eafb37d templater: drop extension point of engine classes (API)
Yuya Nishihara <yuya@tcha.org>
parents: 38352
diff changeset
   795
                self.cache[t] = util.readfile(self._map[t])
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25654
diff changeset
   796
            except KeyError as inst:
36913
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   797
                raise templateutil.TemplateNotFound(
da2977e674a3 templater: extract template evaluation utility to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36912
diff changeset
   798
                    _('"%s" not in template map') % inst.args[0])
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25654
diff changeset
   799
            except IOError as inst:
36500
43e108027b0d py3: move between bytes and unicode when re-raising IOError
Yuya Nishihara <yuya@tcha.org>
parents: 36445
diff changeset
   800
                reason = (_('template file %s: %s')
38353
48289eafb37d templater: drop extension point of engine classes (API)
Yuya Nishihara <yuya@tcha.org>
parents: 38352
diff changeset
   801
                          % (self._map[t],
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37075
diff changeset
   802
                             stringutil.forcebytestr(inst.args[1])))
36500
43e108027b0d py3: move between bytes and unicode when re-raising IOError
Yuya Nishihara <yuya@tcha.org>
parents: 36445
diff changeset
   803
                raise IOError(inst.args[0], encoding.strfromlocal(reason))
38354
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   804
        return self._parse(self.cache[t])
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   805
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   806
    def _parse(self, tmpl):
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   807
        x = parse(tmpl)
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   808
        if self._aliasmap:
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   809
            x = _aliasrules.expand(self._aliasmap, x)
e637dc0b3b1f templater: parse template string to tree by templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38353
diff changeset
   810
        return x
1896
f8f818a04f5b move hgweb template code out to templater
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
   811
38355
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   812
    def _findsymbolsused(self, tree, syms):
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   813
        if not tree:
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   814
            return
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   815
        op = tree[0]
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   816
        if op == 'symbol':
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   817
            s = tree[1]
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   818
            if s in syms[0]:
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   819
                return # avoid recursion: s -> cache[s] -> s
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   820
            syms[0].add(s)
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   821
            if s in self.cache or s in self._map:
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   822
                # s may be a reference for named template
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   823
                self._findsymbolsused(self.load(s), syms)
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   824
            return
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   825
        if op in {'integer', 'string'}:
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   826
            return
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   827
        # '{arg|func}' == '{func(arg)}'
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   828
        if op == '|':
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   829
            syms[1].add(getsymbol(tree[2]))
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   830
            self._findsymbolsused(tree[1], syms)
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   831
            return
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   832
        if op == 'func':
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   833
            syms[1].add(getsymbol(tree[1]))
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   834
            self._findsymbolsused(tree[2], syms)
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   835
            return
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   836
        for x in tree[1:]:
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   837
            self._findsymbolsused(x, syms)
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   838
38438
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   839
    def symbolsused(self, t):
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   840
        """Look up (keywords, filters/functions) referenced from the name
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   841
        template 't'
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   842
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   843
        This may load additional templates from the map file.
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   844
        """
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   845
        syms = (set(), set())
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   846
        self._findsymbolsused(self.load(t), syms)
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   847
        return syms
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   848
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   849
class templater(object):
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   850
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   851
    def __init__(self, filters=None, defaults=None, resources=None,
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   852
                 cache=None, aliases=(), minchunk=1024, maxchunk=65536):
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   853
        """Create template engine optionally with preloaded template fragments
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   854
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   855
        - ``filters``: a dict of functions to transform a value into another.
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   856
        - ``defaults``: a dict of symbol values/functions; may be overridden
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   857
          by a ``mapping`` dict.
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   858
        - ``resources``: a resourcemapper object to look up internal data
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   859
          (e.g. cache), inaccessible from user template.
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   860
        - ``cache``: a dict of preloaded template fragments.
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   861
        - ``aliases``: a list of alias (name, replacement) pairs.
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   862
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   863
        self.cache may be updated later to register additional template
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   864
        fragments.
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   865
        """
38440
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   866
        allfilters = templatefilters.filters.copy()
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   867
        if filters:
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   868
            allfilters.update(filters)
38438
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   869
        self._loader = loader(cache, aliases)
38440
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   870
        self._proc = engine(self._loader.load, allfilters, defaults, resources)
38438
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   871
        self._minchunk, self._maxchunk = minchunk, maxchunk
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   872
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   873
    @classmethod
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   874
    def frommapfile(cls, mapfile, filters=None, defaults=None, resources=None,
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   875
                    cache=None, minchunk=1024, maxchunk=65536):
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   876
        """Create templater from the specified map file"""
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   877
        t = cls(filters, defaults, resources, cache, [], minchunk, maxchunk)
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   878
        cache, tmap, aliases = _readmapfile(mapfile)
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   879
        t._loader.cache.update(cache)
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   880
        t._loader._map = tmap
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   881
        t._loader._aliasmap = _aliasrules.buildmap(aliases)
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   882
        return t
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   883
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   884
    def __contains__(self, key):
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   885
        return key in self._loader
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   886
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   887
    @property
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   888
    def cache(self):
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   889
        return self._loader.cache
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   890
38440
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   891
    # for highlight extension to insert one-time 'colorize' filter
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   892
    @property
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   893
    def _filters(self):
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   894
        return self._proc._filters
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   895
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   896
    @property
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   897
    def defaults(self):
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   898
        return self._proc._defaults
3813c6b7337c templater: remove redundant member variables from templater class
Yuya Nishihara <yuya@tcha.org>
parents: 38439
diff changeset
   899
38438
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   900
    def load(self, t):
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   901
        """Get parsed tree for the given template name. Use a local cache."""
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   902
        return self._loader.load(t)
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   903
38355
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   904
    def symbolsuseddefault(self):
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   905
        """Look up (keywords, filters/functions) referenced from the default
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   906
        unnamed template
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   907
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   908
        This may load additional templates from the map file.
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   909
        """
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   910
        return self.symbolsused('')
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   911
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   912
    def symbolsused(self, t):
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   913
        """Look up (keywords, filters/functions) referenced from the name
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   914
        template 't'
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   915
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   916
        This may load additional templates from the map file.
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   917
        """
38438
f79237942dec templater: extract template loader to separate class
Yuya Nishihara <yuya@tcha.org>
parents: 38355
diff changeset
   918
        return self._loader.symbolsused(t)
38355
d4fae9a0ab1f templater: add function to look up symbols used in template
Yuya Nishihara <yuya@tcha.org>
parents: 38354
diff changeset
   919
36988
317382151ac3 templater: rename .render(mapping) to .renderdefault(mapping) (API)
Yuya Nishihara <yuya@tcha.org>
parents: 36987
diff changeset
   920
    def renderdefault(self, mapping):
32873
2ecce24dfcd3 templater: add simple interface for unnamed template (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32684
diff changeset
   921
        """Render the default unnamed template and return result as string"""
36989
de117f579431 templater: factor out helper that renders named template as string
Yuya Nishihara <yuya@tcha.org>
parents: 36988
diff changeset
   922
        return self.render('', mapping)
de117f579431 templater: factor out helper that renders named template as string
Yuya Nishihara <yuya@tcha.org>
parents: 36988
diff changeset
   923
de117f579431 templater: factor out helper that renders named template as string
Yuya Nishihara <yuya@tcha.org>
parents: 36988
diff changeset
   924
    def render(self, t, mapping):
de117f579431 templater: factor out helper that renders named template as string
Yuya Nishihara <yuya@tcha.org>
parents: 36988
diff changeset
   925
        """Render the specified named template and return result as string"""
37159
b56b79185aad templater: do not use stringify() to concatenate flattened template output
Yuya Nishihara <yuya@tcha.org>
parents: 37157
diff changeset
   926
        return b''.join(self.generate(t, mapping))
32873
2ecce24dfcd3 templater: add simple interface for unnamed template (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32684
diff changeset
   927
37019
c97b936d8bb5 templater: use named function to expand template against mapping dict (API)
Yuya Nishihara <yuya@tcha.org>
parents: 37014
diff changeset
   928
    def generate(self, t, mapping):
c97b936d8bb5 templater: use named function to expand template against mapping dict (API)
Yuya Nishihara <yuya@tcha.org>
parents: 37014
diff changeset
   929
        """Return a generator that renders the specified named template and
c97b936d8bb5 templater: use named function to expand template against mapping dict (API)
Yuya Nishihara <yuya@tcha.org>
parents: 37014
diff changeset
   930
        yields chunks"""
38439
256581484c7f templater: resurrect cache of engine instance
Yuya Nishihara <yuya@tcha.org>
parents: 38438
diff changeset
   931
        stream = self._proc.process(t, mapping)
38351
de089e3eb328 templater: mark most attributes as private
Yuya Nishihara <yuya@tcha.org>
parents: 38285
diff changeset
   932
        if self._minchunk:
de089e3eb328 templater: mark most attributes as private
Yuya Nishihara <yuya@tcha.org>
parents: 38285
diff changeset
   933
            stream = util.increasingchunks(stream, min=self._minchunk,
de089e3eb328 templater: mark most attributes as private
Yuya Nishihara <yuya@tcha.org>
parents: 38285
diff changeset
   934
                                           max=self._maxchunk)
7396
526c40a74bd0 templater: return data in increasing chunk sizes
Brendan Cully <brendan@kublai.com>
parents: 7107
diff changeset
   935
        return stream
7434
cf7741aa1e96 kill some trailing spaces
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7396
diff changeset
   936
22634
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   937
def templatepaths():
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   938
    '''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
   939
    pathsrel = ['templates']
22635
660861a6fad4 templater: inline global 'path' list in templatepaths
Mads Kiilerich <madski@unity3d.com>
parents: 22634
diff changeset
   940
    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
   941
             for f in pathsrel]
660861a6fad4 templater: inline global 'path' list in templatepaths
Mads Kiilerich <madski@unity3d.com>
parents: 22634
diff changeset
   942
    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
   943
22634
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   944
def templatepath(name):
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   945
    '''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
   946
    for p in templatepaths():
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   947
        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
   948
        if os.path.exists(f):
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   949
            return f
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   950
    return None
2189
e3eba577a0ae move changeset_templater into templater module.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2001
diff changeset
   951
9842
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
   952
def stylemap(styles, paths=None):
7966
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   953
    """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
   954
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   955
    Searches mapfile in the following locations:
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   956
    1. templatepath/style/map
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   957
    2. templatepath/map-style
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   958
    3. templatepath/map
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   959
    """
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   960
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   961
    if paths is None:
22634
e48a5d3996c2 templater: introduce templatepaths for getting paths searched for templates
Mads Kiilerich <madski@unity3d.com>
parents: 22633
diff changeset
   962
        paths = templatepaths()
36550
7f6be7121b28 py3: replace type 'str' by 'bytes' in templater.py
Yuya Nishihara <yuya@tcha.org>
parents: 36546
diff changeset
   963
    elif isinstance(paths, bytes):
8223
02145b700fe4 templater: fix little problem from stylemap() changes
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8218
diff changeset
   964
        paths = [paths]
7966
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   965
36550
7f6be7121b28 py3: replace type 'str' by 'bytes' in templater.py
Yuya Nishihara <yuya@tcha.org>
parents: 36546
diff changeset
   966
    if isinstance(styles, bytes):
9842
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
   967
        styles = [styles]
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
   968
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
   969
    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
   970
        # 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
   971
        if (not style
36648
6585ac350fd9 py3: make os.curdir a bytes
Yuya Nishihara <yuya@tcha.org>
parents: 36647
diff changeset
   972
            or style in (pycompat.oscurdir, pycompat.ospardir)
30615
bb77654dc7ae py3: replace os.sep with pycompat.ossep (part 3 of 4)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
   973
            or pycompat.ossep in style
30625
bcf4a975f93d py3: replace os.altsep with pycompat.altsep
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30615
diff changeset
   974
            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
   975
            continue
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
   976
        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
   977
        locations.append('map')
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
   978
d3dbdca92458 hgweb: don't choke when an inexistent style is requested (issue1901)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9372
diff changeset
   979
        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
   980
            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
   981
                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
   982
                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
   983
                    return style, mapfile
7966
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   984
aa983c3d94a9 templater: move stylemap function from hgweb to templater
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7434
diff changeset
   985
    raise RuntimeError("No hgweb templates found in %r" % paths)