##// END OF EJS Templates
templatefilters: prefix helper functions
Patrick Mezard -
r13589:b0a4b05c default
parent child Browse files
Show More
@@ -1,228 +1,228
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 import cgi, re, os, time, urllib
8 import cgi, re, os, time, urllib
9 import encoding, node, util
9 import encoding, node, util
10
10
11 def addbreaks(text):
11 def addbreaks(text):
12 '''replace raw newlines with xhtml line breaks.'''
12 '''replace raw newlines with xhtml line breaks.'''
13 return text.replace('\n', '<br/>\n')
13 return text.replace('\n', '<br/>\n')
14
14
15 agescales = [("year", 3600 * 24 * 365),
15 agescales = [("year", 3600 * 24 * 365),
16 ("month", 3600 * 24 * 30),
16 ("month", 3600 * 24 * 30),
17 ("week", 3600 * 24 * 7),
17 ("week", 3600 * 24 * 7),
18 ("day", 3600 * 24),
18 ("day", 3600 * 24),
19 ("hour", 3600),
19 ("hour", 3600),
20 ("minute", 60),
20 ("minute", 60),
21 ("second", 1)]
21 ("second", 1)]
22
22
23 def age(date):
23 def age(date):
24 '''turn a (timestamp, tzoff) tuple into an age string.'''
24 '''turn a (timestamp, tzoff) tuple into an age string.'''
25
25
26 def plural(t, c):
26 def plural(t, c):
27 if c == 1:
27 if c == 1:
28 return t
28 return t
29 return t + "s"
29 return t + "s"
30 def fmt(t, c):
30 def fmt(t, c):
31 return "%d %s" % (c, plural(t, c))
31 return "%d %s" % (c, plural(t, c))
32
32
33 now = time.time()
33 now = time.time()
34 then = date[0]
34 then = date[0]
35 if then > now:
35 if then > now:
36 return 'in the future'
36 return 'in the future'
37
37
38 delta = max(1, int(now - then))
38 delta = max(1, int(now - then))
39 if delta > agescales[0][1] * 2:
39 if delta > agescales[0][1] * 2:
40 return util.shortdate(date)
40 return util.shortdate(date)
41
41
42 for t, s in agescales:
42 for t, s in agescales:
43 n = delta // s
43 n = delta // s
44 if n >= 2 or s == 1:
44 if n >= 2 or s == 1:
45 return '%s ago' % fmt(t, n)
45 return '%s ago' % fmt(t, n)
46
46
47 def domain(author):
47 def domain(author):
48 '''get domain of author, or empty string if none.'''
48 '''get domain of author, or empty string if none.'''
49 f = author.find('@')
49 f = author.find('@')
50 if f == -1:
50 if f == -1:
51 return ''
51 return ''
52 author = author[f + 1:]
52 author = author[f + 1:]
53 f = author.find('>')
53 f = author.find('>')
54 if f >= 0:
54 if f >= 0:
55 author = author[:f]
55 author = author[:f]
56 return author
56 return author
57
57
58 para_re = None
58 para_re = None
59 space_re = None
59 space_re = None
60
60
61 def fill(text, width):
61 def fill(text, width):
62 '''fill many paragraphs.'''
62 '''fill many paragraphs.'''
63 global para_re, space_re
63 global para_re, space_re
64 if para_re is None:
64 if para_re is None:
65 para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M)
65 para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M)
66 space_re = re.compile(r' +')
66 space_re = re.compile(r' +')
67
67
68 def findparas():
68 def findparas():
69 start = 0
69 start = 0
70 while True:
70 while True:
71 m = para_re.search(text, start)
71 m = para_re.search(text, start)
72 if not m:
72 if not m:
73 uctext = unicode(text[start:], encoding.encoding)
73 uctext = unicode(text[start:], encoding.encoding)
74 w = len(uctext)
74 w = len(uctext)
75 while 0 < w and uctext[w - 1].isspace():
75 while 0 < w and uctext[w - 1].isspace():
76 w -= 1
76 w -= 1
77 yield (uctext[:w].encode(encoding.encoding),
77 yield (uctext[:w].encode(encoding.encoding),
78 uctext[w:].encode(encoding.encoding))
78 uctext[w:].encode(encoding.encoding))
79 break
79 break
80 yield text[start:m.start(0)], m.group(1)
80 yield text[start:m.start(0)], m.group(1)
81 start = m.end(1)
81 start = m.end(1)
82
82
83 return "".join([space_re.sub(' ', util.wrap(para, width=width)) + rest
83 return "".join([space_re.sub(' ', util.wrap(para, width=width)) + rest
84 for para, rest in findparas()])
84 for para, rest in findparas()])
85
85
86 def firstline(text):
86 def firstline(text):
87 '''return the first line of text'''
87 '''return the first line of text'''
88 try:
88 try:
89 return text.splitlines(True)[0].rstrip('\r\n')
89 return text.splitlines(True)[0].rstrip('\r\n')
90 except IndexError:
90 except IndexError:
91 return ''
91 return ''
92
92
93 def indent(text, prefix):
93 def indent(text, prefix):
94 '''indent each non-empty line of text after first with prefix.'''
94 '''indent each non-empty line of text after first with prefix.'''
95 lines = text.splitlines()
95 lines = text.splitlines()
96 num_lines = len(lines)
96 num_lines = len(lines)
97 endswithnewline = text[-1:] == '\n'
97 endswithnewline = text[-1:] == '\n'
98 def indenter():
98 def indenter():
99 for i in xrange(num_lines):
99 for i in xrange(num_lines):
100 l = lines[i]
100 l = lines[i]
101 if i and l.strip():
101 if i and l.strip():
102 yield prefix
102 yield prefix
103 yield l
103 yield l
104 if i < num_lines - 1 or endswithnewline:
104 if i < num_lines - 1 or endswithnewline:
105 yield '\n'
105 yield '\n'
106 return "".join(indenter())
106 return "".join(indenter())
107
107
108 def json(obj):
108 def json(obj):
109 if obj is None or obj is False or obj is True:
109 if obj is None or obj is False or obj is True:
110 return {None: 'null', False: 'false', True: 'true'}[obj]
110 return {None: 'null', False: 'false', True: 'true'}[obj]
111 elif isinstance(obj, int) or isinstance(obj, float):
111 elif isinstance(obj, int) or isinstance(obj, float):
112 return str(obj)
112 return str(obj)
113 elif isinstance(obj, str):
113 elif isinstance(obj, str):
114 u = unicode(obj, encoding.encoding, 'replace')
114 u = unicode(obj, encoding.encoding, 'replace')
115 return '"%s"' % jsonescape(u)
115 return '"%s"' % jsonescape(u)
116 elif isinstance(obj, unicode):
116 elif isinstance(obj, unicode):
117 return '"%s"' % jsonescape(obj)
117 return '"%s"' % jsonescape(obj)
118 elif hasattr(obj, 'keys'):
118 elif hasattr(obj, 'keys'):
119 out = []
119 out = []
120 for k, v in obj.iteritems():
120 for k, v in obj.iteritems():
121 s = '%s: %s' % (json(k), json(v))
121 s = '%s: %s' % (json(k), json(v))
122 out.append(s)
122 out.append(s)
123 return '{' + ', '.join(out) + '}'
123 return '{' + ', '.join(out) + '}'
124 elif hasattr(obj, '__iter__'):
124 elif hasattr(obj, '__iter__'):
125 out = []
125 out = []
126 for i in obj:
126 for i in obj:
127 out.append(json(i))
127 out.append(json(i))
128 return '[' + ', '.join(out) + ']'
128 return '[' + ', '.join(out) + ']'
129 else:
129 else:
130 raise TypeError('cannot encode type %s' % obj.__class__.__name__)
130 raise TypeError('cannot encode type %s' % obj.__class__.__name__)
131
131
132 def uescape(c):
132 def _uescape(c):
133 if ord(c) < 0x80:
133 if ord(c) < 0x80:
134 return c
134 return c
135 else:
135 else:
136 return '\\u%04x' % ord(c)
136 return '\\u%04x' % ord(c)
137
137
138 _escapes = [
138 _escapes = [
139 ('\\', '\\\\'), ('"', '\\"'), ('\t', '\\t'), ('\n', '\\n'),
139 ('\\', '\\\\'), ('"', '\\"'), ('\t', '\\t'), ('\n', '\\n'),
140 ('\r', '\\r'), ('\f', '\\f'), ('\b', '\\b'),
140 ('\r', '\\r'), ('\f', '\\f'), ('\b', '\\b'),
141 ]
141 ]
142
142
143 def jsonescape(s):
143 def jsonescape(s):
144 for k, v in _escapes:
144 for k, v in _escapes:
145 s = s.replace(k, v)
145 s = s.replace(k, v)
146 return ''.join(uescape(c) for c in s)
146 return ''.join(_uescape(c) for c in s)
147
147
148 def nonempty(str):
148 def nonempty(str):
149 return str or "(none)"
149 return str or "(none)"
150
150
151 def obfuscate(text):
151 def obfuscate(text):
152 text = unicode(text, encoding.encoding, 'replace')
152 text = unicode(text, encoding.encoding, 'replace')
153 return ''.join(['&#%d;' % ord(c) for c in text])
153 return ''.join(['&#%d;' % ord(c) for c in text])
154
154
155 def permissions(flags):
155 def permissions(flags):
156 if "l" in flags:
156 if "l" in flags:
157 return "lrwxrwxrwx"
157 return "lrwxrwxrwx"
158 if "x" in flags:
158 if "x" in flags:
159 return "-rwxr-xr-x"
159 return "-rwxr-xr-x"
160 return "-rw-r--r--"
160 return "-rw-r--r--"
161
161
162 def person(author):
162 def person(author):
163 '''get name of author, or else username.'''
163 '''get name of author, or else username.'''
164 if not '@' in author:
164 if not '@' in author:
165 return author
165 return author
166 f = author.find('<')
166 f = author.find('<')
167 if f == -1:
167 if f == -1:
168 return util.shortuser(author)
168 return util.shortuser(author)
169 return author[:f].rstrip()
169 return author[:f].rstrip()
170
170
171 def stringify(thing):
171 def stringify(thing):
172 '''turn nested template iterator into string.'''
172 '''turn nested template iterator into string.'''
173 if hasattr(thing, '__iter__') and not isinstance(thing, str):
173 if hasattr(thing, '__iter__') and not isinstance(thing, str):
174 return "".join([stringify(t) for t in thing if t is not None])
174 return "".join([stringify(t) for t in thing if t is not None])
175 return str(thing)
175 return str(thing)
176
176
177 def stripdir(text):
177 def stripdir(text):
178 '''Treat the text as path and strip a directory level, if possible.'''
178 '''Treat the text as path and strip a directory level, if possible.'''
179 dir = os.path.dirname(text)
179 dir = os.path.dirname(text)
180 if dir == "":
180 if dir == "":
181 return os.path.basename(text)
181 return os.path.basename(text)
182 else:
182 else:
183 return dir
183 return dir
184
184
185 def xmlescape(text):
185 def xmlescape(text):
186 text = (text
186 text = (text
187 .replace('&', '&amp;')
187 .replace('&', '&amp;')
188 .replace('<', '&lt;')
188 .replace('<', '&lt;')
189 .replace('>', '&gt;')
189 .replace('>', '&gt;')
190 .replace('"', '&quot;')
190 .replace('"', '&quot;')
191 .replace("'", '&#39;')) # &apos; invalid in HTML
191 .replace("'", '&#39;')) # &apos; invalid in HTML
192 return re.sub('[\x00-\x08\x0B\x0C\x0E-\x1F]', ' ', text)
192 return re.sub('[\x00-\x08\x0B\x0C\x0E-\x1F]', ' ', text)
193
193
194 filters = {
194 filters = {
195 "addbreaks": addbreaks,
195 "addbreaks": addbreaks,
196 "age": age,
196 "age": age,
197 "basename": os.path.basename,
197 "basename": os.path.basename,
198 "date": lambda x: util.datestr(x),
198 "date": lambda x: util.datestr(x),
199 "domain": domain,
199 "domain": domain,
200 "email": util.email,
200 "email": util.email,
201 "escape": lambda x: cgi.escape(x, True),
201 "escape": lambda x: cgi.escape(x, True),
202 "fill68": lambda x: fill(x, width=68),
202 "fill68": lambda x: fill(x, width=68),
203 "fill76": lambda x: fill(x, width=76),
203 "fill76": lambda x: fill(x, width=76),
204 "firstline": firstline,
204 "firstline": firstline,
205 "hex": node.hex,
205 "hex": node.hex,
206 "hgdate": lambda x: "%d %d" % x,
206 "hgdate": lambda x: "%d %d" % x,
207 "isodate": lambda x: util.datestr(x, '%Y-%m-%d %H:%M %1%2'),
207 "isodate": lambda x: util.datestr(x, '%Y-%m-%d %H:%M %1%2'),
208 "isodatesec": lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2'),
208 "isodatesec": lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2'),
209 "json": json,
209 "json": json,
210 "jsonescape": jsonescape,
210 "jsonescape": jsonescape,
211 "localdate": lambda x: (x[0], util.makedate()[1]),
211 "localdate": lambda x: (x[0], util.makedate()[1]),
212 "nonempty": nonempty,
212 "nonempty": nonempty,
213 "obfuscate": obfuscate,
213 "obfuscate": obfuscate,
214 "permissions": permissions,
214 "permissions": permissions,
215 "person": person,
215 "person": person,
216 "rfc3339date": lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S%1:%2"),
216 "rfc3339date": lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S%1:%2"),
217 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S %1%2"),
217 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S %1%2"),
218 "short": lambda x: x[:12],
218 "short": lambda x: x[:12],
219 "shortdate": util.shortdate,
219 "shortdate": util.shortdate,
220 "stringescape": lambda x: x.encode('string_escape'),
220 "stringescape": lambda x: x.encode('string_escape'),
221 "stringify": stringify,
221 "stringify": stringify,
222 "strip": lambda x: x.strip(),
222 "strip": lambda x: x.strip(),
223 "stripdir": stripdir,
223 "stripdir": stripdir,
224 "tabindent": lambda x: indent(x, '\t'),
224 "tabindent": lambda x: indent(x, '\t'),
225 "urlescape": lambda x: urllib.quote(x),
225 "urlescape": lambda x: urllib.quote(x),
226 "user": lambda x: util.shortuser(x),
226 "user": lambda x: util.shortuser(x),
227 "xmlescape": xmlescape,
227 "xmlescape": xmlescape,
228 }
228 }
General Comments 0
You need to be logged in to leave comments. Login now