templater: preparse templates and cache
authorMatt Mackall <mpm@selenic.com>
Mon, 05 Apr 2010 15:25:08 -0500
changeset 10845 9d8194c2fcbd
parent 10844 6722ba3bf80b
child 10846 594140b1e12d
templater: preparse templates and cache This breaks templates down into a list of literal and {} groups, with group types preidentified.
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
@@ -47,12 +47,16 @@
         self.filters = filters
         self.defaults = defaults
         self.cache = {}
+        self.parsecache = {}
 
     def process(self, t, map):
         '''Perform expansion. t is name of map element to expand. map contains
         added elements for use during expansion. Is a generator.'''
-        tmpl = self.loader(t)
-        iters = [self._process(tmpl, map)]
+        if t not in self.parsecache:
+            tmpl = self.loader(t)
+            self.parsecache[t] = self._parse(tmpl)
+        parsed = self.parsecache[t]
+        iters = [self._process(parsed, map)]
         while iters:
             try:
                 item = iters[0].next()
@@ -100,7 +104,44 @@
             self.cache[expr] = apply
         return self.cache[expr](get)
 
-    def _process(self, tmpl, map):
+    def _parse(self, tmpl):
+        '''preparse a template'''
+
+        parsed = []
+        pos, stop = 0, len(tmpl)
+        while pos < stop:
+            n = tmpl.find('{', pos)
+            if n < 0:
+                parsed.append(('', tmpl[pos:stop]))
+                break
+            if n > 0 and tmpl[n - 1] == '\\':
+                # escaped
+                parsed.append(('', tmpl[pos:n + 1]))
+                pos = n + 1
+                continue
+            if n > pos:
+                parsed.append(('', tmpl[pos:n]))
+
+            pos = n
+            n = tmpl.find('}', pos)
+            if n < 0:
+                # no closing
+                parsed.append(('', tmpl[pos:stop]))
+                break
+
+            expr = tmpl[pos + 1:n]
+            pos = n + 1
+
+            if '%' in expr:
+                parsed.append(('%', expr))
+            elif '|' in expr:
+                parsed.append(('|', expr))
+            else:
+                parsed.append(('g', expr))
+
+        return parsed
+
+    def _process(self, parsed, map):
         '''Render a template. Returns a generator.'''
 
         def get(key):
@@ -111,36 +152,15 @@
                 v = v(**map)
             return v
 
-        pos, stop = 0, len(tmpl)
-        while pos < stop:
-            n = tmpl.find('{', pos)
-            if n < 0:
-                yield tmpl[pos:stop]
-                break
-            if n > 0 and tmpl[n - 1] == '\\':
-                # escaped
-                yield tmpl[pos:n + 1]
-                pos = n + 1
-                continue
-            if n > pos:
-                yield tmpl[pos:n]
-
-            pos = n
-            n = tmpl.find('}', pos)
-            if n < 0:
-                # no closing
-                yield tmpl[pos:stop]
-                break
-
-            expr = tmpl[pos + 1:n]
-            pos = n + 1
-
-            if '%' in expr:
-                yield self._format(expr, get, map)
-            elif '|' in expr:
-                yield self._filter(expr, get, map)
-            else:
-                yield get(expr)
+        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)
 
 engines = {'default': engine}