179 for t, s in agescales: |
179 for t, s in agescales: |
180 n = delta / s |
180 n = delta / s |
181 if n >= 2 or s == 1: |
181 if n >= 2 or s == 1: |
182 return fmt(t, n) |
182 return fmt(t, n) |
183 |
183 |
|
184 def stringify(thing): |
|
185 '''turn nested template iterator into string.''' |
|
186 cs = cStringIO.StringIO() |
|
187 def walk(things): |
|
188 for t in things: |
|
189 if hasattr(t, '__iter__'): |
|
190 walk(t) |
|
191 else: |
|
192 cs.write(t) |
|
193 walk(thing) |
|
194 return cs.getvalue() |
|
195 |
|
196 para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M) |
|
197 space_re = re.compile(r' +') |
|
198 |
|
199 def fill(text, width): |
|
200 '''fill many paragraphs.''' |
|
201 def findparas(): |
|
202 start = 0 |
|
203 while True: |
|
204 m = para_re.search(text, start) |
|
205 if not m: |
|
206 w = len(text) |
|
207 while w > start and text[w-1].isspace(): w -= 1 |
|
208 yield text[start:w], text[w:] |
|
209 break |
|
210 yield text[start:m.start(0)], m.group(1) |
|
211 start = m.end(1) |
|
212 |
|
213 fp = cStringIO.StringIO() |
|
214 for para, rest in findparas(): |
|
215 fp.write(space_re.sub(' ', textwrap.fill(para, width))) |
|
216 fp.write(rest) |
|
217 return fp.getvalue() |
|
218 |
184 def isodate(date): |
219 def isodate(date): |
185 '''turn a (timestamp, tzoff) tuple into an iso 8631 date.''' |
220 '''turn a (timestamp, tzoff) tuple into an iso 8631 date and time.''' |
186 return util.datestr(date, format='%Y-%m-%d %H:%M') |
221 return util.datestr(date, format='%Y-%m-%d %H:%M') |
187 |
222 |
188 def nl2br(text): |
223 def nl2br(text): |
189 '''replace raw newlines with xhtml line breaks.''' |
224 '''replace raw newlines with xhtml line breaks.''' |
190 return text.replace('\n', '<br/>\n') |
225 return text.replace('\n', '<br/>\n') |
199 author = author[f+1:] |
234 author = author[f+1:] |
200 f = author.find('>') |
235 f = author.find('>') |
201 if f >= 0: author = author[:f] |
236 if f >= 0: author = author[:f] |
202 return author |
237 return author |
203 |
238 |
|
239 def email(author): |
|
240 '''get email of author.''' |
|
241 r = author.find('>') |
|
242 if r == -1: r = None |
|
243 return author[author.find('<')+1:r] |
|
244 |
204 def person(author): |
245 def person(author): |
205 '''get name of author, or else username.''' |
246 '''get name of author, or else username.''' |
206 f = author.find('<') |
247 f = author.find('<') |
207 if f == -1: return util.shortuser(author) |
248 if f == -1: return util.shortuser(author) |
208 return author[:f].rstrip() |
249 return author[:f].rstrip() |
209 |
250 |
|
251 def shortdate(date): |
|
252 '''turn (timestamp, tzoff) tuple into iso 8631 date.''' |
|
253 return util.datestr(date, format='%Y-%m-%d', timezone=False) |
|
254 |
|
255 def indent(text, prefix): |
|
256 '''indent each non-empty line of text after first with prefix.''' |
|
257 fp = cStringIO.StringIO() |
|
258 lines = text.splitlines() |
|
259 num_lines = len(lines) |
|
260 for i in xrange(num_lines): |
|
261 l = lines[i] |
|
262 if i and l.strip(): fp.write(prefix) |
|
263 fp.write(l) |
|
264 if i < num_lines - 1 or text.endswith('\n'): |
|
265 fp.write('\n') |
|
266 return fp.getvalue() |
|
267 |
210 common_filters = { |
268 common_filters = { |
211 "addbreaks": nl2br, |
269 "addbreaks": nl2br, |
212 "age": age, |
270 "age": age, |
213 "date": lambda x: util.datestr(x), |
271 "date": lambda x: util.datestr(x), |
214 "domain": domain, |
272 "domain": domain, |
|
273 "email": email, |
215 "escape": lambda x: cgi.escape(x, True), |
274 "escape": lambda x: cgi.escape(x, True), |
|
275 "fill68": lambda x: fill(x, width=68), |
|
276 "fill76": lambda x: fill(x, width=76), |
216 "firstline": lambda x: x.splitlines(1)[0].rstrip('\r\n'), |
277 "firstline": lambda x: x.splitlines(1)[0].rstrip('\r\n'), |
|
278 "tabindent": lambda x: indent(x, '\t'), |
217 "isodate": isodate, |
279 "isodate": isodate, |
218 "obfuscate": obfuscate, |
280 "obfuscate": obfuscate, |
219 "permissions": lambda x: x and "-rwxr-xr-x" or "-rw-r--r--", |
281 "permissions": lambda x: x and "-rwxr-xr-x" or "-rw-r--r--", |
220 "person": person, |
282 "person": person, |
221 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"), |
283 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"), |
222 "short": lambda x: x[:12], |
284 "short": lambda x: x[:12], |
|
285 "shortdate": shortdate, |
|
286 "stringify": stringify, |
223 "strip": lambda x: x.strip(), |
287 "strip": lambda x: x.strip(), |
224 "urlescape": lambda x: urllib.quote(x), |
288 "urlescape": lambda x: urllib.quote(x), |
225 "user": lambda x: util.shortuser(x), |
289 "user": lambda x: util.shortuser(x), |
226 } |
290 } |
227 |
291 |