comparison mercurial/templater.py @ 34330:89aec1834a86

templatekw: add new-style template expansion to {manifest} The goal is to allow us to easily access to nested data. The dot operator will be introduced later so we can write '{p1.files}' instead of '{revset("p1()") % "{files}"}' for example. In the example above, 'p1' needs to carry a mapping dict along with its string representation. If it were a list or a dict, it could be wrapped semi-transparently with the _hybrid class, but for non-list/dict types, it would be difficult to proxy all necessary functions to underlying value type because several core operations may conflict with the ones of the underlying value: - hash(value) should be different from hash(wrapped(value)), which means dict[wrapped(value)] would be invalid - 'value == wrapped(value)' would be false, breaks 'ifcontains' - len(wrapped(value)) may be either len(value) or len(iter(wrapped(value))) So the wrapper has no proxy functions and its scope designed to be minimal. It's unwrapped at eval*() functions so we don't have to care for a wrapped object unless it's really needed: # most template functions just call evalfuncarg() unwrapped_value = evalfuncarg(context, mapping, args[n]) # if wrapped value is needed, use evalrawexp() maybe_wrapped_value = evalrawexp(context, mapping, args[n]) Another idea was to wrap every template variable with a tagging class, but which seemed uneasy without a static type checker. This patch updates {manifest} to a mappable as an example.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 24 Apr 2016 18:41:23 +0900
parents 6367318327f0
children 46f45b7efa30
comparison
equal deleted inserted replaced
34329:6367318327f0 34330:89aec1834a86
305 return func(context, mapping, data) 305 return func(context, mapping, data)
306 306
307 def evalfuncarg(context, mapping, arg): 307 def evalfuncarg(context, mapping, arg):
308 """Evaluate given argument as value type""" 308 """Evaluate given argument as value type"""
309 thing = evalrawexp(context, mapping, arg) 309 thing = evalrawexp(context, mapping, arg)
310 thing = templatekw.unwrapvalue(thing)
310 # evalrawexp() may return string, generator of strings or arbitrary object 311 # evalrawexp() may return string, generator of strings or arbitrary object
311 # such as date tuple, but filter does not want generator. 312 # such as date tuple, but filter does not want generator.
312 if isinstance(thing, types.GeneratorType): 313 if isinstance(thing, types.GeneratorType):
313 thing = stringify(thing) 314 thing = stringify(thing)
314 return thing 315 return thing
321 if thing is None: 322 if thing is None:
322 # not a template keyword, takes as a boolean literal 323 # not a template keyword, takes as a boolean literal
323 thing = util.parsebool(data) 324 thing = util.parsebool(data)
324 else: 325 else:
325 thing = func(context, mapping, data) 326 thing = func(context, mapping, data)
327 thing = templatekw.unwrapvalue(thing)
326 if isinstance(thing, bool): 328 if isinstance(thing, bool):
327 return thing 329 return thing
328 # other objects are evaluated as strings, which means 0 is True, but 330 # other objects are evaluated as strings, which means 0 is True, but
329 # empty dict/list should be False as they are expected to be '' 331 # empty dict/list should be False as they are expected to be ''
330 return bool(stringify(thing)) 332 return bool(stringify(thing))
766 raise error.ParseError(_("join expects one or two arguments")) 768 raise error.ParseError(_("join expects one or two arguments"))
767 769
768 # TODO: perhaps this should be evalfuncarg(), but it can't because hgweb 770 # TODO: perhaps this should be evalfuncarg(), but it can't because hgweb
769 # abuses generator as a keyword that returns a list of dicts. 771 # abuses generator as a keyword that returns a list of dicts.
770 joinset = evalrawexp(context, mapping, args[0]) 772 joinset = evalrawexp(context, mapping, args[0])
773 joinset = templatekw.unwrapvalue(joinset)
771 joinfmt = getattr(joinset, 'joinfmt', pycompat.identity) 774 joinfmt = getattr(joinset, 'joinfmt', pycompat.identity)
772 joiner = " " 775 joiner = " "
773 if len(args) > 1: 776 if len(args) > 1:
774 joiner = evalstring(context, mapping, args[1]) 777 joiner = evalstring(context, mapping, args[1])
775 778