Mercurial > public > mercurial-scm > hg
comparison mercurial/templater.py @ 10846:594140b1e12d
templater: extend preparsing
preparse filters and formats and supply functions to apply
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 05 Apr 2010 15:25:08 -0500 |
parents | 9d8194c2fcbd |
children | 90f4367535a5 |
comparison
equal
deleted
inserted
replaced
10845:9d8194c2fcbd | 10846:594140b1e12d |
---|---|
70 elif hasattr(item, '__iter__'): | 70 elif hasattr(item, '__iter__'): |
71 iters.insert(0, iter(item)) | 71 iters.insert(0, iter(item)) |
72 else: | 72 else: |
73 yield str(item) | 73 yield str(item) |
74 | 74 |
75 def _format(self, expr, get, map): | |
76 key, format = expr.split('%') | |
77 v = get(key) | |
78 if not hasattr(v, '__iter__'): | |
79 raise SyntaxError(_("error expanding '%s%%%s'") % (key, format)) | |
80 lm = map.copy() | |
81 for i in v: | |
82 if isinstance(i, dict): | |
83 lm.update(i) | |
84 yield self.process(format, lm) | |
85 else: | |
86 # v is not an iterable of dicts, this happen when 'key' | |
87 # has been fully expanded already and format is useless. | |
88 # If so, return the expanded value. | |
89 yield i | |
90 | |
91 def _filter(self, expr, get, map): | |
92 if expr not in self.cache: | |
93 parts = expr.split('|') | |
94 val = parts[0] | |
95 try: | |
96 filters = [self.filters[f] for f in parts[1:]] | |
97 except KeyError, i: | |
98 raise SyntaxError(_("unknown filter '%s'") % i[0]) | |
99 def apply(get): | |
100 x = get(val) | |
101 for f in filters: | |
102 x = f(x) | |
103 return x | |
104 self.cache[expr] = apply | |
105 return self.cache[expr](get) | |
106 | |
107 def _parse(self, tmpl): | 75 def _parse(self, tmpl): |
108 '''preparse a template''' | 76 '''preparse a template''' |
77 | |
78 def getter(mapping, key): | |
79 v = mapping.get(key) | |
80 if v is None: | |
81 v = self.defaults.get(key, '') | |
82 if hasattr(v, '__call__'): | |
83 v = v(**mapping) | |
84 return v | |
85 | |
86 def raw(mapping, x): | |
87 return x | |
88 def filt(mapping, parts): | |
89 filters, val = parts | |
90 x = getter(mapping, val) | |
91 for f in filters: | |
92 x = f(x) | |
93 return x | |
94 def formatter(mapping, args): | |
95 key, format = args | |
96 v = getter(mapping, key) | |
97 if not hasattr(v, '__iter__'): | |
98 raise SyntaxError(_("error expanding '%s%%%s'") | |
99 % (key, format)) | |
100 lm = mapping.copy() | |
101 for i in v: | |
102 if isinstance(i, dict): | |
103 lm.update(i) | |
104 yield self.process(format, lm) | |
105 else: | |
106 # v is not an iterable of dicts, this happen when 'key' | |
107 # has been fully expanded already and format is useless. | |
108 # If so, return the expanded value. | |
109 yield i | |
109 | 110 |
110 parsed = [] | 111 parsed = [] |
111 pos, stop = 0, len(tmpl) | 112 pos, stop = 0, len(tmpl) |
112 while pos < stop: | 113 while pos < stop: |
113 n = tmpl.find('{', pos) | 114 n = tmpl.find('{', pos) |
114 if n < 0: | 115 if n < 0: |
115 parsed.append(('', tmpl[pos:stop])) | 116 parsed.append((raw, tmpl[pos:stop])) |
116 break | 117 break |
117 if n > 0 and tmpl[n - 1] == '\\': | 118 if n > 0 and tmpl[n - 1] == '\\': |
118 # escaped | 119 # escaped |
119 parsed.append(('', tmpl[pos:n + 1])) | 120 parsed.append((raw, tmpl[pos:n + 1])) |
120 pos = n + 1 | 121 pos = n + 1 |
121 continue | 122 continue |
122 if n > pos: | 123 if n > pos: |
123 parsed.append(('', tmpl[pos:n])) | 124 parsed.append((raw, tmpl[pos:n])) |
124 | 125 |
125 pos = n | 126 pos = n |
126 n = tmpl.find('}', pos) | 127 n = tmpl.find('}', pos) |
127 if n < 0: | 128 if n < 0: |
128 # no closing | 129 # no closing |
129 parsed.append(('', tmpl[pos:stop])) | 130 parsed.append((raw, tmpl[pos:stop])) |
130 break | 131 break |
131 | 132 |
132 expr = tmpl[pos + 1:n] | 133 expr = tmpl[pos + 1:n] |
133 pos = n + 1 | 134 pos = n + 1 |
134 | 135 |
135 if '%' in expr: | 136 if '%' in expr: |
136 parsed.append(('%', expr)) | 137 parsed.append((formatter, expr.split('%'))) |
137 elif '|' in expr: | 138 elif '|' in expr: |
138 parsed.append(('|', expr)) | 139 parts = expr.split('|') |
140 val = parts[0] | |
141 try: | |
142 filters = [self.filters[f] for f in parts[1:]] | |
143 except KeyError, i: | |
144 raise SyntaxError(_("unknown filter '%s'") % i[0]) | |
145 parsed.append((filt, (filters, val))) | |
139 else: | 146 else: |
140 parsed.append(('g', expr)) | 147 parsed.append((getter, expr)) |
141 | 148 |
142 return parsed | 149 return parsed |
143 | 150 |
144 def _process(self, parsed, map): | 151 def _process(self, parsed, mapping): |
145 '''Render a template. Returns a generator.''' | 152 '''Render a template. Returns a generator.''' |
146 | 153 for f, e in parsed: |
147 def get(key): | 154 yield f(mapping, e) |
148 v = map.get(key) | |
149 if v is None: | |
150 v = self.defaults.get(key, '') | |
151 if hasattr(v, '__call__'): | |
152 v = v(**map) | |
153 return v | |
154 | |
155 for t, e in parsed: | |
156 if not t: | |
157 yield e | |
158 elif t is '|': | |
159 yield self._filter(e, get, map) | |
160 elif t is '%': | |
161 yield self._format(e, get, map) | |
162 elif t is 'g': | |
163 yield get(e) | |
164 | 155 |
165 engines = {'default': engine} | 156 engines = {'default': engine} |
166 | 157 |
167 class templater(object): | 158 class templater(object): |
168 | 159 |