templater: extend preparsing
authorMatt Mackall <mpm@selenic.com>
Mon, 05 Apr 2010 15:25:08 -0500
changeset 10846 594140b1e12d
parent 10845 9d8194c2fcbd
child 10847 90f4367535a5
templater: extend preparsing preparse filters and formats and supply functions to apply
mercurial/templater.py
--- a/mercurial/templater.py	Mon Apr 05 15:25:08 2010 -0500
+++ b/mercurial/templater.py	Mon Apr 05 15:25:08 2010 -0500
@@ -72,95 +72,86 @@
             else:
                 yield str(item)
 
-    def _format(self, expr, get, map):
-        key, format = expr.split('%')
-        v = get(key)
-        if not hasattr(v, '__iter__'):
-            raise SyntaxError(_("error expanding '%s%%%s'") % (key, format))
-        lm = map.copy()
-        for i in v:
-            if isinstance(i, dict):
-                lm.update(i)
-                yield self.process(format, lm)
-            else:
-                # v is not an iterable of dicts, this happen when 'key'
-                # has been fully expanded already and format is useless.
-                # If so, return the expanded value.
-                yield i
-
-    def _filter(self, expr, get, map):
-        if expr not in self.cache:
-            parts = expr.split('|')
-            val = parts[0]
-            try:
-                filters = [self.filters[f] for f in parts[1:]]
-            except KeyError, i:
-                raise SyntaxError(_("unknown filter '%s'") % i[0])
-            def apply(get):
-                x = get(val)
-                for f in filters:
-                    x = f(x)
-                return x
-            self.cache[expr] = apply
-        return self.cache[expr](get)
-
     def _parse(self, tmpl):
         '''preparse a template'''
 
+        def getter(mapping, key):
+            v = mapping.get(key)
+            if v is None:
+                v = self.defaults.get(key, '')
+            if hasattr(v, '__call__'):
+                v = v(**mapping)
+            return v
+
+        def raw(mapping, x):
+            return x
+        def filt(mapping, parts):
+            filters, val = parts
+            x = getter(mapping, val)
+            for f in filters:
+                x = f(x)
+            return x
+        def formatter(mapping, args):
+            key, format = args
+            v = getter(mapping, key)
+            if not hasattr(v, '__iter__'):
+                raise SyntaxError(_("error expanding '%s%%%s'")
+                                  % (key, format))
+            lm = mapping.copy()
+            for i in v:
+                if isinstance(i, dict):
+                    lm.update(i)
+                    yield self.process(format, lm)
+                else:
+                    # v is not an iterable of dicts, this happen when 'key'
+                    # has been fully expanded already and format is useless.
+                    # If so, return the expanded value.
+                    yield i
+
         parsed = []
         pos, stop = 0, len(tmpl)
         while pos < stop:
             n = tmpl.find('{', pos)
             if n < 0:
-                parsed.append(('', tmpl[pos:stop]))
+                parsed.append((raw, tmpl[pos:stop]))
                 break
             if n > 0 and tmpl[n - 1] == '\\':
                 # escaped
-                parsed.append(('', tmpl[pos:n + 1]))
+                parsed.append((raw, tmpl[pos:n + 1]))
                 pos = n + 1
                 continue
             if n > pos:
-                parsed.append(('', tmpl[pos:n]))
+                parsed.append((raw, tmpl[pos:n]))
 
             pos = n
             n = tmpl.find('}', pos)
             if n < 0:
                 # no closing
-                parsed.append(('', tmpl[pos:stop]))
+                parsed.append((raw, tmpl[pos:stop]))
                 break
 
             expr = tmpl[pos + 1:n]
             pos = n + 1
 
             if '%' in expr:
-                parsed.append(('%', expr))
+                parsed.append((formatter, expr.split('%')))
             elif '|' in expr:
-                parsed.append(('|', expr))
+                parts = expr.split('|')
+                val = parts[0]
+                try:
+                    filters = [self.filters[f] for f in parts[1:]]
+                except KeyError, i:
+                    raise SyntaxError(_("unknown filter '%s'") % i[0])
+                parsed.append((filt, (filters, val)))
             else:
-                parsed.append(('g', expr))
+                parsed.append((getter, expr))
 
         return parsed
 
-    def _process(self, parsed, map):
+    def _process(self, parsed, mapping):
         '''Render a template. Returns a generator.'''
-
-        def get(key):
-            v = map.get(key)
-            if v is None:
-                v = self.defaults.get(key, '')
-            if hasattr(v, '__call__'):
-                v = v(**map)
-            return v
-
-        for t, e in parsed:
-            if not t:
-                yield e
-            elif t is '|':
-                yield self._filter(e, get, map)
-            elif t is '%':
-                yield self._format(e, get, map)
-            elif t is 'g':
-                yield get(e)
+        for f, e in parsed:
+            yield f(mapping, e)
 
 engines = {'default': engine}