##// END OF EJS Templates
templater: add dot operator to easily access a sub item...
Yuya Nishihara -
r34536:78590585 default
parent child Browse files
Show More
@@ -72,6 +72,11 As seen in the above example, ``{templat
72 To prevent it from being interpreted, you can use an escape character ``\{``
72 To prevent it from being interpreted, you can use an escape character ``\{``
73 or a raw string prefix, ``r'...'``.
73 or a raw string prefix, ``r'...'``.
74
74
75 The dot operator can be used as a shorthand for accessing a sub item:
76
77 - ``expr.member`` is roughly equivalent to ``expr % "{member}"`` if ``expr``
78 returns a non-list/dict. The returned value is not stringified.
79
75 Aliases
80 Aliases
76 =======
81 =======
77
82
@@ -73,6 +73,7 class _mappable(object):
73 This class allows us to handle both:
73 This class allows us to handle both:
74 - "{manifest}"
74 - "{manifest}"
75 - "{manifest % '{rev}:{node}'}"
75 - "{manifest % '{rev}:{node}'}"
76 - "{manifest.rev}"
76
77
77 Unlike a _hybrid, this does not simulate the behavior of the underling
78 Unlike a _hybrid, this does not simulate the behavior of the underling
78 value. Use unwrapvalue() or unwraphybrid() to obtain the inner object.
79 value. Use unwrapvalue() or unwraphybrid() to obtain the inner object.
@@ -35,6 +35,7 from . import (
35 elements = {
35 elements = {
36 # token-type: binding-strength, primary, prefix, infix, suffix
36 # token-type: binding-strength, primary, prefix, infix, suffix
37 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
37 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
38 ".": (18, None, None, (".", 18), None),
38 "%": (15, None, None, ("%", 15), None),
39 "%": (15, None, None, ("%", 15), None),
39 "|": (15, None, None, ("|", 15), None),
40 "|": (15, None, None, ("|", 15), None),
40 "*": (5, None, None, ("*", 5), None),
41 "*": (5, None, None, ("*", 5), None),
@@ -60,7 +61,7 def tokenize(program, start, end, term=N
60 c = program[pos]
61 c = program[pos]
61 if c.isspace(): # skip inter-token whitespace
62 if c.isspace(): # skip inter-token whitespace
62 pass
63 pass
63 elif c in "(=,)%|+-*/": # handle simple operators
64 elif c in "(=,).%|+-*/": # handle simple operators
64 yield (c, None, pos)
65 yield (c, None, pos)
65 elif c in '"\'': # handle quoted templates
66 elif c in '"\'': # handle quoted templates
66 s = pos + 1
67 s = pos + 1
@@ -450,6 +451,26 def runmap(context, mapping, data):
450 # If so, return the expanded value.
451 # If so, return the expanded value.
451 yield v
452 yield v
452
453
454 def buildmember(exp, context):
455 darg = compileexp(exp[1], context, methods)
456 memb = getsymbol(exp[2])
457 return (runmember, (darg, memb))
458
459 def runmember(context, mapping, data):
460 darg, memb = data
461 d = evalrawexp(context, mapping, darg)
462 if util.safehasattr(d, 'tomap'):
463 lm = mapping.copy()
464 lm.update(d.tomap())
465 return runsymbol(context, lm, memb)
466 # TODO: d.get(memb) if dict-like?
467
468 sym = findsymbolicname(darg)
469 if sym:
470 raise error.ParseError(_("keyword '%s' has no member") % sym)
471 else:
472 raise error.ParseError(_("%r has no member") % d)
473
453 def buildnegate(exp, context):
474 def buildnegate(exp, context):
454 arg = compileexp(exp[1], context, exprmethods)
475 arg = compileexp(exp[1], context, exprmethods)
455 return (runnegate, arg)
476 return (runnegate, arg)
@@ -1152,7 +1173,7 exprmethods = {
1152 "symbol": lambda e, c: (runsymbol, e[1]),
1173 "symbol": lambda e, c: (runsymbol, e[1]),
1153 "template": buildtemplate,
1174 "template": buildtemplate,
1154 "group": lambda e, c: compileexp(e[1], c, exprmethods),
1175 "group": lambda e, c: compileexp(e[1], c, exprmethods),
1155 # ".": buildmember,
1176 ".": buildmember,
1156 "|": buildfilter,
1177 "|": buildfilter,
1157 "%": buildmap,
1178 "%": buildmap,
1158 "func": buildfunc,
1179 "func": buildfunc,
@@ -3147,6 +3147,51 Test manifest/get() can be join()-ed as
3147 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), "")}\n'
3147 $ hg log -R latesttag -r tip -T '{join(get(extras, "branch"), "")}\n'
3148 default
3148 default
3149
3149
3150 Test dot operator precedence:
3151
3152 $ hg debugtemplate -R latesttag -r0 -v '{manifest.node|short}\n'
3153 (template
3154 (|
3155 (.
3156 (symbol 'manifest')
3157 (symbol 'node'))
3158 (symbol 'short'))
3159 (string '\n'))
3160 89f4071fec70
3161
3162 (the following examples are invalid, but seem natural in parsing POV)
3163
3164 $ hg debugtemplate -R latesttag -r0 -v '{foo|bar.baz}\n' 2> /dev/null
3165 (template
3166 (|
3167 (symbol 'foo')
3168 (.
3169 (symbol 'bar')
3170 (symbol 'baz')))
3171 (string '\n'))
3172 [255]
3173 $ hg debugtemplate -R latesttag -r0 -v '{foo.bar()}\n' 2> /dev/null
3174 (template
3175 (.
3176 (symbol 'foo')
3177 (func
3178 (symbol 'bar')
3179 None))
3180 (string '\n'))
3181 [255]
3182
3183 Test evaluation of dot operator:
3184
3185 $ hg log -R latesttag -l1 -T '{min(revset("0:9")).node}\n'
3186 ce3cec86e6c26bd9bdfc590a6b92abc9680f1796
3187
3188 $ hg log -R latesttag -l1 -T '{author.invalid}\n'
3189 hg: parse error: keyword 'author' has no member
3190 [255]
3191 $ hg log -R latesttag -l1 -T '{min("abc").invalid}\n'
3192 hg: parse error: 'a' has no member
3193 [255]
3194
3150 Test the sub function of templating for expansion:
3195 Test the sub function of templating for expansion:
3151
3196
3152 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
3197 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
General Comments 0
You need to be logged in to leave comments. Login now