Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/templater.py @ 1909:37b9f80a5fbb
add doc comments to template code.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Mon, 27 Feb 2006 15:07:25 -0800 |
parents | 9dec2479622d |
children | b288b4bb8448 |
comparison
equal
deleted
inserted
replaced
1908:be71c04d62c0 | 1909:37b9f80a5fbb |
---|---|
1 # templater.py - template expansion for output | |
2 # | |
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 # | |
5 # This software may be used and distributed according to the terms | |
6 # of the GNU General Public License, incorporated herein by reference. | |
7 | |
1 import re | 8 import re |
2 from demandload import demandload | 9 from demandload import demandload |
3 from i18n import gettext as _ | 10 from i18n import gettext as _ |
4 demandload(globals(), "cStringIO cgi os time urllib util") | 11 demandload(globals(), "cStringIO cgi os time urllib util") |
5 | 12 |
10 'n': '\n', | 17 'n': '\n', |
11 'v': '\v', | 18 'v': '\v', |
12 } | 19 } |
13 | 20 |
14 def parsestring(s, quoted=True): | 21 def parsestring(s, quoted=True): |
22 '''parse a string using simple c-like syntax. | |
23 string must be in quotes if quoted is True.''' | |
15 fp = cStringIO.StringIO() | 24 fp = cStringIO.StringIO() |
16 if quoted: | 25 if quoted: |
17 first = s[0] | 26 first = s[0] |
18 if len(s) < 2: raise SyntaxError(_('string too short')) | 27 if len(s) < 2: raise SyntaxError(_('string too short')) |
19 if first not in "'\"": raise SyntaxError(_('invalid quote')) | 28 if first not in "'\"": raise SyntaxError(_('invalid quote')) |
29 else: fp.write(c) | 38 else: fp.write(c) |
30 if escape: raise SyntaxError(_('unterminated escape')) | 39 if escape: raise SyntaxError(_('unterminated escape')) |
31 return fp.getvalue() | 40 return fp.getvalue() |
32 | 41 |
33 class templater(object): | 42 class templater(object): |
43 '''template expansion engine. | |
44 | |
45 template expansion works like this. a map file contains key=value | |
46 pairs. if value is quoted, it is treated as string. otherwise, it | |
47 is treated as name of template file. | |
48 | |
49 templater is asked to expand a key in map. it looks up key, and | |
50 looks for atrings like this: {foo}. it expands {foo} by looking up | |
51 foo in map, and substituting it. expansion is recursive: it stops | |
52 when there is no more {foo} to replace. | |
53 | |
54 expansion also allows formatting and filtering. | |
55 | |
56 format uses key to expand each item in list. syntax is | |
57 {key%format}. | |
58 | |
59 filter uses function to transform value. syntax is | |
60 {key|filter1|filter2|...}.''' | |
61 | |
34 def __init__(self, mapfile, filters={}, defaults={}): | 62 def __init__(self, mapfile, filters={}, defaults={}): |
63 '''set up template engine. | |
64 mapfile is name of file to read map definitions from. | |
65 filters is dict of functions. each transforms a value into another. | |
66 defaults is dict of default map definitions.''' | |
35 self.mapfile = mapfile or 'template' | 67 self.mapfile = mapfile or 'template' |
36 self.cache = {} | 68 self.cache = {} |
37 self.map = {} | 69 self.map = {} |
38 self.base = (mapfile and os.path.dirname(mapfile)) or '' | 70 self.base = (mapfile and os.path.dirname(mapfile)) or '' |
39 self.filters = filters | 71 self.filters = filters |
62 | 94 |
63 def __contains__(self, key): | 95 def __contains__(self, key): |
64 return key in self.cache | 96 return key in self.cache |
65 | 97 |
66 def __call__(self, t, **map): | 98 def __call__(self, t, **map): |
99 '''perform expansion. | |
100 t is name of map element to expand. | |
101 map is added elements to use during expansion.''' | |
67 m = self.defaults.copy() | 102 m = self.defaults.copy() |
68 m.update(map) | 103 m.update(map) |
69 try: | 104 try: |
70 tmpl = self.cache[t] | 105 tmpl = self.cache[t] |
71 except KeyError: | 106 except KeyError: |
125 ("month", 3600 * 24 * 30), | 160 ("month", 3600 * 24 * 30), |
126 ("year", 3600 * 24 * 365)] | 161 ("year", 3600 * 24 * 365)] |
127 | 162 |
128 agescales.reverse() | 163 agescales.reverse() |
129 | 164 |
130 def age(x): | 165 def age(date): |
166 '''turn a (timestamp, tzoff) tuple into an age string.''' | |
167 | |
131 def plural(t, c): | 168 def plural(t, c): |
132 if c == 1: | 169 if c == 1: |
133 return t | 170 return t |
134 return t + "s" | 171 return t + "s" |
135 def fmt(t, c): | 172 def fmt(t, c): |
136 return "%d %s" % (c, plural(t, c)) | 173 return "%d %s" % (c, plural(t, c)) |
137 | 174 |
138 now = time.time() | 175 now = time.time() |
139 then = x[0] | 176 then = date[0] |
140 delta = max(1, int(now - then)) | 177 delta = max(1, int(now - then)) |
141 | 178 |
142 for t, s in agescales: | 179 for t, s in agescales: |
143 n = delta / s | 180 n = delta / s |
144 if n >= 2 or s == 1: | 181 if n >= 2 or s == 1: |
145 return fmt(t, n) | 182 return fmt(t, n) |
146 | 183 |
147 def isodate(date): | 184 def isodate(date): |
185 '''turn a (timestamp, tzoff) tuple into an iso 8631 date.''' | |
148 return util.datestr(date, format='%Y-%m-%d %H:%M') | 186 return util.datestr(date, format='%Y-%m-%d %H:%M') |
149 | 187 |
150 def nl2br(text): | 188 def nl2br(text): |
189 '''replace raw newlines with xhtml line breaks.''' | |
151 return text.replace('\n', '<br/>\n') | 190 return text.replace('\n', '<br/>\n') |
152 | 191 |
153 def obfuscate(text): | 192 def obfuscate(text): |
154 return ''.join(['&#%d;' % ord(c) for c in text]) | 193 return ''.join(['&#%d;' % ord(c) for c in text]) |
155 | 194 |
156 def domain(author): | 195 def domain(author): |
196 '''get domain of author, or empty string if none.''' | |
157 f = author.find('@') | 197 f = author.find('@') |
158 if f == -1: return '' | 198 if f == -1: return '' |
159 author = author[f+1:] | 199 author = author[f+1:] |
160 f = author.find('>') | 200 f = author.find('>') |
161 if f >= 0: author = author[:f] | 201 if f >= 0: author = author[:f] |
162 return author | 202 return author |
163 | 203 |
164 def person(author): | 204 def person(author): |
205 '''get name of author, or else username.''' | |
165 f = author.find('<') | 206 f = author.find('<') |
166 if f == -1: return util.shortuser(author) | 207 if f == -1: return util.shortuser(author) |
167 return author[:f].rstrip() | 208 return author[:f].rstrip() |
168 | 209 |
169 common_filters = { | 210 common_filters = { |
183 "urlescape": urllib.quote, | 224 "urlescape": urllib.quote, |
184 "user": util.shortuser, | 225 "user": util.shortuser, |
185 } | 226 } |
186 | 227 |
187 def templatepath(name=None): | 228 def templatepath(name=None): |
229 '''return location of template file or directory (if no name). | |
230 returns None if not found.''' | |
188 for f in 'templates', '../templates': | 231 for f in 'templates', '../templates': |
189 fl = f.split('/') | 232 fl = f.split('/') |
190 if name: fl.append(name) | 233 if name: fl.append(name) |
191 p = os.path.join(os.path.dirname(__file__), *fl) | 234 p = os.path.join(os.path.dirname(__file__), *fl) |
192 if (name and os.path.exists(p)) or os.path.isdir(p): | 235 if (name and os.path.exists(p)) or os.path.isdir(p): |