[RFC] [PATCH] Support arguments in template expandos

Rocco Rutte pdmef at gmx.net
Thu May 7 11:08:36 CDT 2009


Hi,

in order to provide different messages for different terms instead of
just "(none)" through the nonempty template filter, I extended the
templater to support arguments for keys and filters like so:

    {key ["arg1" ["arg2" ...]]|filter1 ["arg1" ["arg2" ...]]|...}

Arguments for filters could be used like this:

    {desc|...|nonempty "no description"}

Arguments for keys can be used like this:

    {tr "changeset"}

to translate the term changeset (i.e. make hgweb internationalized --
though I have no idea how to manage translation files, but using "tr"
works).

The most ugly parts currently are:

- the arguments for keys are passed in the map with key = 'args'

- the 'tr' key is hardcoded across all templater instances

For filters, the patch allows both the new and new python syntax (so I
don't have to touch too many places for just a proof-of-concept).

The patch is against current crew. Comments? Ideas? Suggestions?

Rocco

diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -41,8 +41,11 @@ class engine(object):
     filter uses function to transform value. syntax is
     {key|filter1|filter2|...}.'''
 
-    template_re = re.compile(r"(?:(?:#(?=[\w\|%]+#))|(?:{(?=[\w\|%]+})))"
-                             r"(\w+)(?:(?:%(\w+))|((?:\|\w+)*))[#}]")
+    template_re = re.compile(r"(?:(?:#(?=[\w\s\"\|%]+#))|(?:{(?=[\w\s\"\|%]+})))"
+                             r"(\w+(?:\s\"[^\"]*\")*)(?:(?:%(\w+(?:\s\"[^\"]*\")*))|"
+                             r"((?:\|\w+(?:\s\"[^\"]*\")*)*))[#}]")
+
+    args_re = re.compile(r"\"\s\"")
 
     def __init__(self, loader, filters={}, defaults={}):
         self.loader = loader
@@ -71,6 +74,15 @@ class engine(object):
 
     def _process(self, tmpl, map):
         '''Render a template. Returns a generator.'''
+
+        def _splitargs(s):
+            key = s.split(' ')[0]
+            args = [s[len(key):]]
+            if '"' in args[0]:
+                args = self.args_re.split(args[0])
+                args = [a.lstrip(' ').lstrip('"').rstrip('"') for a in args]
+            return key, args
+
         while tmpl:
             m = self.template_re.search(tmpl)
             if not m:
@@ -84,11 +96,13 @@ class engine(object):
                 yield tmpl[:start]
             tmpl = tmpl[end:]
 
+            key, args = _splitargs(key)
             if key in map:
                 v = map[key]
             else:
                 v = self.defaults.get(key, "")
             if callable(v):
+                map['args'] = args
                 v = v(**map)
             if format:
                 if not hasattr(v, '__iter__'):
@@ -101,9 +115,16 @@ class engine(object):
             else:
                 if fl:
                     for f in fl.split("|")[1:]:
-                        v = self.filters[f](v)
+                        key, args = _splitargs(f)
+                        try:
+                            v = self.filters[key](v, args)
+                        except TypeError:
+                            v = self.filters[key](v)
                 yield v
 
+def translate(**args):
+    return ' '.join([_(a) for a in args['args']])
+
 class templater(object):
 
     def __init__(self, mapfile, filters={}, defaults={}, cache={},
@@ -120,6 +141,8 @@ class templater(object):
         self.defaults = defaults
         self.minchunk, self.maxchunk = minchunk, maxchunk
 
+        self.defaults['tr'] = translate
+
         if not mapfile:
             return
         if not os.path.exists(mapfile):


More information about the Mercurial-devel mailing list