##// END OF EJS Templates
templatefilters: add missing import of _
Mads Kiilerich -
r18730:a5d33446 stable
parent child Browse files
Show More
@@ -1,424 +1,425 b''
1 # template-filters.py - common template expansion filters
1 # template-filters.py - common template expansion filters
2 #
2 #
3 # Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 import cgi, re, os, time, urllib
9 import cgi, re, os, time, urllib
9 import encoding, node, util, error
10 import encoding, node, util, error
10 import hbisect
11 import hbisect
11
12
12 def addbreaks(text):
13 def addbreaks(text):
13 """:addbreaks: Any text. Add an XHTML "<br />" tag before the end of
14 """:addbreaks: Any text. Add an XHTML "<br />" tag before the end of
14 every line except the last.
15 every line except the last.
15 """
16 """
16 return text.replace('\n', '<br/>\n')
17 return text.replace('\n', '<br/>\n')
17
18
18 agescales = [("year", 3600 * 24 * 365),
19 agescales = [("year", 3600 * 24 * 365),
19 ("month", 3600 * 24 * 30),
20 ("month", 3600 * 24 * 30),
20 ("week", 3600 * 24 * 7),
21 ("week", 3600 * 24 * 7),
21 ("day", 3600 * 24),
22 ("day", 3600 * 24),
22 ("hour", 3600),
23 ("hour", 3600),
23 ("minute", 60),
24 ("minute", 60),
24 ("second", 1)]
25 ("second", 1)]
25
26
26 def age(date):
27 def age(date):
27 """:age: Date. Returns a human-readable date/time difference between the
28 """:age: Date. Returns a human-readable date/time difference between the
28 given date/time and the current date/time.
29 given date/time and the current date/time.
29 """
30 """
30
31
31 def plural(t, c):
32 def plural(t, c):
32 if c == 1:
33 if c == 1:
33 return t
34 return t
34 return t + "s"
35 return t + "s"
35 def fmt(t, c):
36 def fmt(t, c):
36 return "%d %s" % (c, plural(t, c))
37 return "%d %s" % (c, plural(t, c))
37
38
38 now = time.time()
39 now = time.time()
39 then = date[0]
40 then = date[0]
40 future = False
41 future = False
41 if then > now:
42 if then > now:
42 future = True
43 future = True
43 delta = max(1, int(then - now))
44 delta = max(1, int(then - now))
44 if delta > agescales[0][1] * 30:
45 if delta > agescales[0][1] * 30:
45 return 'in the distant future'
46 return 'in the distant future'
46 else:
47 else:
47 delta = max(1, int(now - then))
48 delta = max(1, int(now - then))
48 if delta > agescales[0][1] * 2:
49 if delta > agescales[0][1] * 2:
49 return util.shortdate(date)
50 return util.shortdate(date)
50
51
51 for t, s in agescales:
52 for t, s in agescales:
52 n = delta // s
53 n = delta // s
53 if n >= 2 or s == 1:
54 if n >= 2 or s == 1:
54 if future:
55 if future:
55 return '%s from now' % fmt(t, n)
56 return '%s from now' % fmt(t, n)
56 return '%s ago' % fmt(t, n)
57 return '%s ago' % fmt(t, n)
57
58
58 def basename(path):
59 def basename(path):
59 """:basename: Any text. Treats the text as a path, and returns the last
60 """:basename: Any text. Treats the text as a path, and returns the last
60 component of the path after splitting by the path separator
61 component of the path after splitting by the path separator
61 (ignoring trailing separators). For example, "foo/bar/baz" becomes
62 (ignoring trailing separators). For example, "foo/bar/baz" becomes
62 "baz" and "foo/bar//" becomes "bar".
63 "baz" and "foo/bar//" becomes "bar".
63 """
64 """
64 return os.path.basename(path)
65 return os.path.basename(path)
65
66
66 def datefilter(text):
67 def datefilter(text):
67 """:date: Date. Returns a date in a Unix date format, including the
68 """:date: Date. Returns a date in a Unix date format, including the
68 timezone: "Mon Sep 04 15:13:13 2006 0700".
69 timezone: "Mon Sep 04 15:13:13 2006 0700".
69 """
70 """
70 return util.datestr(text)
71 return util.datestr(text)
71
72
72 def domain(author):
73 def domain(author):
73 """:domain: Any text. Finds the first string that looks like an email
74 """:domain: Any text. Finds the first string that looks like an email
74 address, and extracts just the domain component. Example: ``User
75 address, and extracts just the domain component. Example: ``User
75 <user@example.com>`` becomes ``example.com``.
76 <user@example.com>`` becomes ``example.com``.
76 """
77 """
77 f = author.find('@')
78 f = author.find('@')
78 if f == -1:
79 if f == -1:
79 return ''
80 return ''
80 author = author[f + 1:]
81 author = author[f + 1:]
81 f = author.find('>')
82 f = author.find('>')
82 if f >= 0:
83 if f >= 0:
83 author = author[:f]
84 author = author[:f]
84 return author
85 return author
85
86
86 def email(text):
87 def email(text):
87 """:email: Any text. Extracts the first string that looks like an email
88 """:email: Any text. Extracts the first string that looks like an email
88 address. Example: ``User <user@example.com>`` becomes
89 address. Example: ``User <user@example.com>`` becomes
89 ``user@example.com``.
90 ``user@example.com``.
90 """
91 """
91 return util.email(text)
92 return util.email(text)
92
93
93 def escape(text):
94 def escape(text):
94 """:escape: Any text. Replaces the special XML/XHTML characters "&", "<"
95 """:escape: Any text. Replaces the special XML/XHTML characters "&", "<"
95 and ">" with XML entities, and filters out NUL characters.
96 and ">" with XML entities, and filters out NUL characters.
96 """
97 """
97 return cgi.escape(text.replace('\0', ''), True)
98 return cgi.escape(text.replace('\0', ''), True)
98
99
99 para_re = None
100 para_re = None
100 space_re = None
101 space_re = None
101
102
102 def fill(text, width):
103 def fill(text, width):
103 '''fill many paragraphs.'''
104 '''fill many paragraphs.'''
104 global para_re, space_re
105 global para_re, space_re
105 if para_re is None:
106 if para_re is None:
106 para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M)
107 para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M)
107 space_re = re.compile(r' +')
108 space_re = re.compile(r' +')
108
109
109 def findparas():
110 def findparas():
110 start = 0
111 start = 0
111 while True:
112 while True:
112 m = para_re.search(text, start)
113 m = para_re.search(text, start)
113 if not m:
114 if not m:
114 uctext = unicode(text[start:], encoding.encoding)
115 uctext = unicode(text[start:], encoding.encoding)
115 w = len(uctext)
116 w = len(uctext)
116 while 0 < w and uctext[w - 1].isspace():
117 while 0 < w and uctext[w - 1].isspace():
117 w -= 1
118 w -= 1
118 yield (uctext[:w].encode(encoding.encoding),
119 yield (uctext[:w].encode(encoding.encoding),
119 uctext[w:].encode(encoding.encoding))
120 uctext[w:].encode(encoding.encoding))
120 break
121 break
121 yield text[start:m.start(0)], m.group(1)
122 yield text[start:m.start(0)], m.group(1)
122 start = m.end(1)
123 start = m.end(1)
123
124
124 return "".join([space_re.sub(' ', util.wrap(para, width=width)) + rest
125 return "".join([space_re.sub(' ', util.wrap(para, width=width)) + rest
125 for para, rest in findparas()])
126 for para, rest in findparas()])
126
127
127 def fill68(text):
128 def fill68(text):
128 """:fill68: Any text. Wraps the text to fit in 68 columns."""
129 """:fill68: Any text. Wraps the text to fit in 68 columns."""
129 return fill(text, 68)
130 return fill(text, 68)
130
131
131 def fill76(text):
132 def fill76(text):
132 """:fill76: Any text. Wraps the text to fit in 76 columns."""
133 """:fill76: Any text. Wraps the text to fit in 76 columns."""
133 return fill(text, 76)
134 return fill(text, 76)
134
135
135 def firstline(text):
136 def firstline(text):
136 """:firstline: Any text. Returns the first line of text."""
137 """:firstline: Any text. Returns the first line of text."""
137 try:
138 try:
138 return text.splitlines(True)[0].rstrip('\r\n')
139 return text.splitlines(True)[0].rstrip('\r\n')
139 except IndexError:
140 except IndexError:
140 return ''
141 return ''
141
142
142 def hexfilter(text):
143 def hexfilter(text):
143 """:hex: Any text. Convert a binary Mercurial node identifier into
144 """:hex: Any text. Convert a binary Mercurial node identifier into
144 its long hexadecimal representation.
145 its long hexadecimal representation.
145 """
146 """
146 return node.hex(text)
147 return node.hex(text)
147
148
148 def hgdate(text):
149 def hgdate(text):
149 """:hgdate: Date. Returns the date as a pair of numbers: "1157407993
150 """:hgdate: Date. Returns the date as a pair of numbers: "1157407993
150 25200" (Unix timestamp, timezone offset).
151 25200" (Unix timestamp, timezone offset).
151 """
152 """
152 return "%d %d" % text
153 return "%d %d" % text
153
154
154 def isodate(text):
155 def isodate(text):
155 """:isodate: Date. Returns the date in ISO 8601 format: "2009-08-18 13:00
156 """:isodate: Date. Returns the date in ISO 8601 format: "2009-08-18 13:00
156 +0200".
157 +0200".
157 """
158 """
158 return util.datestr(text, '%Y-%m-%d %H:%M %1%2')
159 return util.datestr(text, '%Y-%m-%d %H:%M %1%2')
159
160
160 def isodatesec(text):
161 def isodatesec(text):
161 """:isodatesec: Date. Returns the date in ISO 8601 format, including
162 """:isodatesec: Date. Returns the date in ISO 8601 format, including
162 seconds: "2009-08-18 13:00:13 +0200". See also the rfc3339date
163 seconds: "2009-08-18 13:00:13 +0200". See also the rfc3339date
163 filter.
164 filter.
164 """
165 """
165 return util.datestr(text, '%Y-%m-%d %H:%M:%S %1%2')
166 return util.datestr(text, '%Y-%m-%d %H:%M:%S %1%2')
166
167
167 def indent(text, prefix):
168 def indent(text, prefix):
168 '''indent each non-empty line of text after first with prefix.'''
169 '''indent each non-empty line of text after first with prefix.'''
169 lines = text.splitlines()
170 lines = text.splitlines()
170 num_lines = len(lines)
171 num_lines = len(lines)
171 endswithnewline = text[-1:] == '\n'
172 endswithnewline = text[-1:] == '\n'
172 def indenter():
173 def indenter():
173 for i in xrange(num_lines):
174 for i in xrange(num_lines):
174 l = lines[i]
175 l = lines[i]
175 if i and l.strip():
176 if i and l.strip():
176 yield prefix
177 yield prefix
177 yield l
178 yield l
178 if i < num_lines - 1 or endswithnewline:
179 if i < num_lines - 1 or endswithnewline:
179 yield '\n'
180 yield '\n'
180 return "".join(indenter())
181 return "".join(indenter())
181
182
182 def json(obj):
183 def json(obj):
183 if obj is None or obj is False or obj is True:
184 if obj is None or obj is False or obj is True:
184 return {None: 'null', False: 'false', True: 'true'}[obj]
185 return {None: 'null', False: 'false', True: 'true'}[obj]
185 elif isinstance(obj, int) or isinstance(obj, float):
186 elif isinstance(obj, int) or isinstance(obj, float):
186 return str(obj)
187 return str(obj)
187 elif isinstance(obj, str):
188 elif isinstance(obj, str):
188 u = unicode(obj, encoding.encoding, 'replace')
189 u = unicode(obj, encoding.encoding, 'replace')
189 return '"%s"' % jsonescape(u)
190 return '"%s"' % jsonescape(u)
190 elif isinstance(obj, unicode):
191 elif isinstance(obj, unicode):
191 return '"%s"' % jsonescape(obj)
192 return '"%s"' % jsonescape(obj)
192 elif util.safehasattr(obj, 'keys'):
193 elif util.safehasattr(obj, 'keys'):
193 out = []
194 out = []
194 for k, v in obj.iteritems():
195 for k, v in obj.iteritems():
195 s = '%s: %s' % (json(k), json(v))
196 s = '%s: %s' % (json(k), json(v))
196 out.append(s)
197 out.append(s)
197 return '{' + ', '.join(out) + '}'
198 return '{' + ', '.join(out) + '}'
198 elif util.safehasattr(obj, '__iter__'):
199 elif util.safehasattr(obj, '__iter__'):
199 out = []
200 out = []
200 for i in obj:
201 for i in obj:
201 out.append(json(i))
202 out.append(json(i))
202 return '[' + ', '.join(out) + ']'
203 return '[' + ', '.join(out) + ']'
203 else:
204 else:
204 raise TypeError('cannot encode type %s' % obj.__class__.__name__)
205 raise TypeError('cannot encode type %s' % obj.__class__.__name__)
205
206
206 def _uescape(c):
207 def _uescape(c):
207 if ord(c) < 0x80:
208 if ord(c) < 0x80:
208 return c
209 return c
209 else:
210 else:
210 return '\\u%04x' % ord(c)
211 return '\\u%04x' % ord(c)
211
212
212 _escapes = [
213 _escapes = [
213 ('\\', '\\\\'), ('"', '\\"'), ('\t', '\\t'), ('\n', '\\n'),
214 ('\\', '\\\\'), ('"', '\\"'), ('\t', '\\t'), ('\n', '\\n'),
214 ('\r', '\\r'), ('\f', '\\f'), ('\b', '\\b'),
215 ('\r', '\\r'), ('\f', '\\f'), ('\b', '\\b'),
215 ]
216 ]
216
217
217 def jsonescape(s):
218 def jsonescape(s):
218 for k, v in _escapes:
219 for k, v in _escapes:
219 s = s.replace(k, v)
220 s = s.replace(k, v)
220 return ''.join(_uescape(c) for c in s)
221 return ''.join(_uescape(c) for c in s)
221
222
222 def localdate(text):
223 def localdate(text):
223 """:localdate: Date. Converts a date to local date."""
224 """:localdate: Date. Converts a date to local date."""
224 return (util.parsedate(text)[0], util.makedate()[1])
225 return (util.parsedate(text)[0], util.makedate()[1])
225
226
226 def nonempty(str):
227 def nonempty(str):
227 """:nonempty: Any text. Returns '(none)' if the string is empty."""
228 """:nonempty: Any text. Returns '(none)' if the string is empty."""
228 return str or "(none)"
229 return str or "(none)"
229
230
230 def obfuscate(text):
231 def obfuscate(text):
231 """:obfuscate: Any text. Returns the input text rendered as a sequence of
232 """:obfuscate: Any text. Returns the input text rendered as a sequence of
232 XML entities.
233 XML entities.
233 """
234 """
234 text = unicode(text, encoding.encoding, 'replace')
235 text = unicode(text, encoding.encoding, 'replace')
235 return ''.join(['&#%d;' % ord(c) for c in text])
236 return ''.join(['&#%d;' % ord(c) for c in text])
236
237
237 def permissions(flags):
238 def permissions(flags):
238 if "l" in flags:
239 if "l" in flags:
239 return "lrwxrwxrwx"
240 return "lrwxrwxrwx"
240 if "x" in flags:
241 if "x" in flags:
241 return "-rwxr-xr-x"
242 return "-rwxr-xr-x"
242 return "-rw-r--r--"
243 return "-rw-r--r--"
243
244
244 def person(author):
245 def person(author):
245 """:person: Any text. Returns the name before an email address,
246 """:person: Any text. Returns the name before an email address,
246 interpreting it as per RFC 5322.
247 interpreting it as per RFC 5322.
247
248
248 >>> person('foo@bar')
249 >>> person('foo@bar')
249 'foo'
250 'foo'
250 >>> person('Foo Bar <foo@bar>')
251 >>> person('Foo Bar <foo@bar>')
251 'Foo Bar'
252 'Foo Bar'
252 >>> person('"Foo Bar" <foo@bar>')
253 >>> person('"Foo Bar" <foo@bar>')
253 'Foo Bar'
254 'Foo Bar'
254 >>> person('"Foo \"buz\" Bar" <foo@bar>')
255 >>> person('"Foo \"buz\" Bar" <foo@bar>')
255 'Foo "buz" Bar'
256 'Foo "buz" Bar'
256 >>> # The following are invalid, but do exist in real-life
257 >>> # The following are invalid, but do exist in real-life
257 ...
258 ...
258 >>> person('Foo "buz" Bar <foo@bar>')
259 >>> person('Foo "buz" Bar <foo@bar>')
259 'Foo "buz" Bar'
260 'Foo "buz" Bar'
260 >>> person('"Foo Bar <foo@bar>')
261 >>> person('"Foo Bar <foo@bar>')
261 'Foo Bar'
262 'Foo Bar'
262 """
263 """
263 if '@' not in author:
264 if '@' not in author:
264 return author
265 return author
265 f = author.find('<')
266 f = author.find('<')
266 if f != -1:
267 if f != -1:
267 return author[:f].strip(' "').replace('\\"', '"')
268 return author[:f].strip(' "').replace('\\"', '"')
268 f = author.find('@')
269 f = author.find('@')
269 return author[:f].replace('.', ' ')
270 return author[:f].replace('.', ' ')
270
271
271 def rfc3339date(text):
272 def rfc3339date(text):
272 """:rfc3339date: Date. Returns a date using the Internet date format
273 """:rfc3339date: Date. Returns a date using the Internet date format
273 specified in RFC 3339: "2009-08-18T13:00:13+02:00".
274 specified in RFC 3339: "2009-08-18T13:00:13+02:00".
274 """
275 """
275 return util.datestr(text, "%Y-%m-%dT%H:%M:%S%1:%2")
276 return util.datestr(text, "%Y-%m-%dT%H:%M:%S%1:%2")
276
277
277 def rfc822date(text):
278 def rfc822date(text):
278 """:rfc822date: Date. Returns a date using the same format used in email
279 """:rfc822date: Date. Returns a date using the same format used in email
279 headers: "Tue, 18 Aug 2009 13:00:13 +0200".
280 headers: "Tue, 18 Aug 2009 13:00:13 +0200".
280 """
281 """
281 return util.datestr(text, "%a, %d %b %Y %H:%M:%S %1%2")
282 return util.datestr(text, "%a, %d %b %Y %H:%M:%S %1%2")
282
283
283 def short(text):
284 def short(text):
284 """:short: Changeset hash. Returns the short form of a changeset hash,
285 """:short: Changeset hash. Returns the short form of a changeset hash,
285 i.e. a 12 hexadecimal digit string.
286 i.e. a 12 hexadecimal digit string.
286 """
287 """
287 return text[:12]
288 return text[:12]
288
289
289 def shortbisect(text):
290 def shortbisect(text):
290 """:shortbisect: Any text. Treats `text` as a bisection status, and
291 """:shortbisect: Any text. Treats `text` as a bisection status, and
291 returns a single-character representing the status (G: good, B: bad,
292 returns a single-character representing the status (G: good, B: bad,
292 S: skipped, U: untested, I: ignored). Returns single space if `text`
293 S: skipped, U: untested, I: ignored). Returns single space if `text`
293 is not a valid bisection status.
294 is not a valid bisection status.
294 """
295 """
295 return hbisect.shortlabel(text) or ' '
296 return hbisect.shortlabel(text) or ' '
296
297
297 def shortdate(text):
298 def shortdate(text):
298 """:shortdate: Date. Returns a date like "2006-09-18"."""
299 """:shortdate: Date. Returns a date like "2006-09-18"."""
299 return util.shortdate(text)
300 return util.shortdate(text)
300
301
301 def stringescape(text):
302 def stringescape(text):
302 return text.encode('string_escape')
303 return text.encode('string_escape')
303
304
304 def stringify(thing):
305 def stringify(thing):
305 """:stringify: Any type. Turns the value into text by converting values into
306 """:stringify: Any type. Turns the value into text by converting values into
306 text and concatenating them.
307 text and concatenating them.
307 """
308 """
308 if util.safehasattr(thing, '__iter__') and not isinstance(thing, str):
309 if util.safehasattr(thing, '__iter__') and not isinstance(thing, str):
309 return "".join([stringify(t) for t in thing if t is not None])
310 return "".join([stringify(t) for t in thing if t is not None])
310 return str(thing)
311 return str(thing)
311
312
312 def strip(text):
313 def strip(text):
313 """:strip: Any text. Strips all leading and trailing whitespace."""
314 """:strip: Any text. Strips all leading and trailing whitespace."""
314 return text.strip()
315 return text.strip()
315
316
316 def stripdir(text):
317 def stripdir(text):
317 """:stripdir: Treat the text as path and strip a directory level, if
318 """:stripdir: Treat the text as path and strip a directory level, if
318 possible. For example, "foo" and "foo/bar" becomes "foo".
319 possible. For example, "foo" and "foo/bar" becomes "foo".
319 """
320 """
320 dir = os.path.dirname(text)
321 dir = os.path.dirname(text)
321 if dir == "":
322 if dir == "":
322 return os.path.basename(text)
323 return os.path.basename(text)
323 else:
324 else:
324 return dir
325 return dir
325
326
326 def tabindent(text):
327 def tabindent(text):
327 """:tabindent: Any text. Returns the text, with every line except the
328 """:tabindent: Any text. Returns the text, with every line except the
328 first starting with a tab character.
329 first starting with a tab character.
329 """
330 """
330 return indent(text, '\t')
331 return indent(text, '\t')
331
332
332 def urlescape(text):
333 def urlescape(text):
333 """:urlescape: Any text. Escapes all "special" characters. For example,
334 """:urlescape: Any text. Escapes all "special" characters. For example,
334 "foo bar" becomes "foo%20bar".
335 "foo bar" becomes "foo%20bar".
335 """
336 """
336 return urllib.quote(text)
337 return urllib.quote(text)
337
338
338 def userfilter(text):
339 def userfilter(text):
339 """:user: Any text. Returns a short representation of a user name or email
340 """:user: Any text. Returns a short representation of a user name or email
340 address."""
341 address."""
341 return util.shortuser(text)
342 return util.shortuser(text)
342
343
343 def emailuser(text):
344 def emailuser(text):
344 """:emailuser: Any text. Returns the user portion of an email address."""
345 """:emailuser: Any text. Returns the user portion of an email address."""
345 return util.emailuser(text)
346 return util.emailuser(text)
346
347
347 def xmlescape(text):
348 def xmlescape(text):
348 text = (text
349 text = (text
349 .replace('&', '&amp;')
350 .replace('&', '&amp;')
350 .replace('<', '&lt;')
351 .replace('<', '&lt;')
351 .replace('>', '&gt;')
352 .replace('>', '&gt;')
352 .replace('"', '&quot;')
353 .replace('"', '&quot;')
353 .replace("'", '&#39;')) # &apos; invalid in HTML
354 .replace("'", '&#39;')) # &apos; invalid in HTML
354 return re.sub('[\x00-\x08\x0B\x0C\x0E-\x1F]', ' ', text)
355 return re.sub('[\x00-\x08\x0B\x0C\x0E-\x1F]', ' ', text)
355
356
356 filters = {
357 filters = {
357 "addbreaks": addbreaks,
358 "addbreaks": addbreaks,
358 "age": age,
359 "age": age,
359 "basename": basename,
360 "basename": basename,
360 "date": datefilter,
361 "date": datefilter,
361 "domain": domain,
362 "domain": domain,
362 "email": email,
363 "email": email,
363 "escape": escape,
364 "escape": escape,
364 "fill68": fill68,
365 "fill68": fill68,
365 "fill76": fill76,
366 "fill76": fill76,
366 "firstline": firstline,
367 "firstline": firstline,
367 "hex": hexfilter,
368 "hex": hexfilter,
368 "hgdate": hgdate,
369 "hgdate": hgdate,
369 "isodate": isodate,
370 "isodate": isodate,
370 "isodatesec": isodatesec,
371 "isodatesec": isodatesec,
371 "json": json,
372 "json": json,
372 "jsonescape": jsonescape,
373 "jsonescape": jsonescape,
373 "localdate": localdate,
374 "localdate": localdate,
374 "nonempty": nonempty,
375 "nonempty": nonempty,
375 "obfuscate": obfuscate,
376 "obfuscate": obfuscate,
376 "permissions": permissions,
377 "permissions": permissions,
377 "person": person,
378 "person": person,
378 "rfc3339date": rfc3339date,
379 "rfc3339date": rfc3339date,
379 "rfc822date": rfc822date,
380 "rfc822date": rfc822date,
380 "short": short,
381 "short": short,
381 "shortbisect": shortbisect,
382 "shortbisect": shortbisect,
382 "shortdate": shortdate,
383 "shortdate": shortdate,
383 "stringescape": stringescape,
384 "stringescape": stringescape,
384 "stringify": stringify,
385 "stringify": stringify,
385 "strip": strip,
386 "strip": strip,
386 "stripdir": stripdir,
387 "stripdir": stripdir,
387 "tabindent": tabindent,
388 "tabindent": tabindent,
388 "urlescape": urlescape,
389 "urlescape": urlescape,
389 "user": userfilter,
390 "user": userfilter,
390 "emailuser": emailuser,
391 "emailuser": emailuser,
391 "xmlescape": xmlescape,
392 "xmlescape": xmlescape,
392 }
393 }
393
394
394 def fillfunc(context, mapping, args):
395 def fillfunc(context, mapping, args):
395 if not (1 <= len(args) <= 2):
396 if not (1 <= len(args) <= 2):
396 raise error.ParseError(_("fill expects one or two arguments"))
397 raise error.ParseError(_("fill expects one or two arguments"))
397
398
398 text = stringify(args[0][0](context, mapping, args[0][1]))
399 text = stringify(args[0][0](context, mapping, args[0][1]))
399 width = 76
400 width = 76
400 if len(args) == 2:
401 if len(args) == 2:
401 try:
402 try:
402 width = int(stringify(args[1][0](context, mapping, args[1][1])))
403 width = int(stringify(args[1][0](context, mapping, args[1][1])))
403 except ValueError:
404 except ValueError:
404 raise error.ParseError(_("fill expects an integer width"))
405 raise error.ParseError(_("fill expects an integer width"))
405
406
406 return fill(text, width)
407 return fill(text, width)
407
408
408 def datefunc(context, mapping, args):
409 def datefunc(context, mapping, args):
409 if not (1 <= len(args) <= 2):
410 if not (1 <= len(args) <= 2):
410 raise error.ParseError(_("date expects one or two arguments"))
411 raise error.ParseError(_("date expects one or two arguments"))
411
412
412 date = args[0][0](context, mapping, args[0][1])
413 date = args[0][0](context, mapping, args[0][1])
413 if len(args) == 2:
414 if len(args) == 2:
414 fmt = stringify(args[1][0](context, mapping, args[1][1]))
415 fmt = stringify(args[1][0](context, mapping, args[1][1]))
415 return util.datestr(date, fmt)
416 return util.datestr(date, fmt)
416 return util.datestr(date)
417 return util.datestr(date)
417
418
418 funcs = {
419 funcs = {
419 "fill": fillfunc,
420 "fill": fillfunc,
420 "date": datefunc,
421 "date": datefunc,
421 }
422 }
422
423
423 # tell hggettext to extract docstrings from these functions:
424 # tell hggettext to extract docstrings from these functions:
424 i18nfunctions = filters.values()
425 i18nfunctions = filters.values()
General Comments 0
You need to be logged in to leave comments. Login now