Mercurial > public > mercurial-scm > hg
comparison mercurial/templatefilters.py @ 13591:264f292a0c6f
templatefilters: move doc from templates.txt to docstrings
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Sat, 12 Mar 2011 12:46:31 +0100 |
parents | 1a752dcfe062 |
children | cc4721ed7a2a |
comparison
equal
deleted
inserted
replaced
13590:1a752dcfe062 | 13591:264f292a0c6f |
---|---|
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 from i18n import gettext | |
10 | 11 |
11 def addbreaks(text): | 12 def addbreaks(text): |
12 '''replace raw newlines with xhtml line breaks.''' | 13 """:addbreaks: Any text. Add an XHTML "<br />" tag before the end of |
14 every line except the last. | |
15 """ | |
13 return text.replace('\n', '<br/>\n') | 16 return text.replace('\n', '<br/>\n') |
14 | 17 |
15 agescales = [("year", 3600 * 24 * 365), | 18 agescales = [("year", 3600 * 24 * 365), |
16 ("month", 3600 * 24 * 30), | 19 ("month", 3600 * 24 * 30), |
17 ("week", 3600 * 24 * 7), | 20 ("week", 3600 * 24 * 7), |
19 ("hour", 3600), | 22 ("hour", 3600), |
20 ("minute", 60), | 23 ("minute", 60), |
21 ("second", 1)] | 24 ("second", 1)] |
22 | 25 |
23 def age(date): | 26 def age(date): |
24 '''turn a (timestamp, tzoff) tuple into an age string.''' | 27 """:age: Date. Returns a human-readable date/time difference between the |
28 given date/time and the current date/time. | |
29 """ | |
25 | 30 |
26 def plural(t, c): | 31 def plural(t, c): |
27 if c == 1: | 32 if c == 1: |
28 return t | 33 return t |
29 return t + "s" | 34 return t + "s" |
43 n = delta // s | 48 n = delta // s |
44 if n >= 2 or s == 1: | 49 if n >= 2 or s == 1: |
45 return '%s ago' % fmt(t, n) | 50 return '%s ago' % fmt(t, n) |
46 | 51 |
47 def basename(path): | 52 def basename(path): |
53 """:basename: Any text. Treats the text as a path, and returns the last | |
54 component of the path after splitting by the path separator | |
55 (ignoring trailing separators). For example, "foo/bar/baz" becomes | |
56 "baz" and "foo/bar//" becomes "bar". | |
57 """ | |
48 return os.path.basename(path) | 58 return os.path.basename(path) |
49 | 59 |
50 def datefilter(text): | 60 def datefilter(text): |
61 """:date: Date. Returns a date in a Unix date format, including the | |
62 timezone: "Mon Sep 04 15:13:13 2006 0700". | |
63 """ | |
51 return util.datestr(text) | 64 return util.datestr(text) |
52 | 65 |
53 def domain(author): | 66 def domain(author): |
54 '''get domain of author, or empty string if none.''' | 67 """:domain: Any text. Finds the first string that looks like an email |
68 address, and extracts just the domain component. Example: ``User | |
69 <user@example.com>`` becomes ``example.com``. | |
70 """ | |
55 f = author.find('@') | 71 f = author.find('@') |
56 if f == -1: | 72 if f == -1: |
57 return '' | 73 return '' |
58 author = author[f + 1:] | 74 author = author[f + 1:] |
59 f = author.find('>') | 75 f = author.find('>') |
60 if f >= 0: | 76 if f >= 0: |
61 author = author[:f] | 77 author = author[:f] |
62 return author | 78 return author |
63 | 79 |
64 def email(text): | 80 def email(text): |
81 """:email: Any text. Extracts the first string that looks like an email | |
82 address. Example: ``User <user@example.com>`` becomes | |
83 ``user@example.com``. | |
84 """ | |
65 return util.email(text) | 85 return util.email(text) |
66 | 86 |
67 def escape(text): | 87 def escape(text): |
88 """:escape: Any text. Replaces the special XML/XHTML characters "&", "<" | |
89 and ">" with XML entities. | |
90 """ | |
68 return cgi.escape(text, True) | 91 return cgi.escape(text, True) |
69 | 92 |
70 para_re = None | 93 para_re = None |
71 space_re = None | 94 space_re = None |
72 | 95 |
94 | 117 |
95 return "".join([space_re.sub(' ', util.wrap(para, width=width)) + rest | 118 return "".join([space_re.sub(' ', util.wrap(para, width=width)) + rest |
96 for para, rest in findparas()]) | 119 for para, rest in findparas()]) |
97 | 120 |
98 def fill68(text): | 121 def fill68(text): |
122 """:fill68: Any text. Wraps the text to fit in 68 columns.""" | |
99 return fill(text, 68) | 123 return fill(text, 68) |
100 | 124 |
101 def fill76(text): | 125 def fill76(text): |
126 """:fill76: Any text. Wraps the text to fit in 76 columns.""" | |
102 return fill(text, 76) | 127 return fill(text, 76) |
103 | 128 |
104 def firstline(text): | 129 def firstline(text): |
105 '''return the first line of text''' | 130 """:firstline: Any text. Returns the first line of text.""" |
106 try: | 131 try: |
107 return text.splitlines(True)[0].rstrip('\r\n') | 132 return text.splitlines(True)[0].rstrip('\r\n') |
108 except IndexError: | 133 except IndexError: |
109 return '' | 134 return '' |
110 | 135 |
111 def hexfilter(text): | 136 def hexfilter(text): |
137 """:hex: Any text. Convert a binary Mercurial node identifier into | |
138 its long hexadecimal representation. | |
139 """ | |
112 return node.hex(text) | 140 return node.hex(text) |
113 | 141 |
114 def hgdate(text): | 142 def hgdate(text): |
143 """:hgdate: Date. Returns the date as a pair of numbers: "1157407993 | |
144 25200" (Unix timestamp, timezone offset). | |
145 """ | |
115 return "%d %d" % text | 146 return "%d %d" % text |
116 | 147 |
117 def isodate(text): | 148 def isodate(text): |
149 """:isodate: Date. Returns the date in ISO 8601 format: "2009-08-18 13:00 | |
150 +0200". | |
151 """ | |
118 return util.datestr(text, '%Y-%m-%d %H:%M %1%2') | 152 return util.datestr(text, '%Y-%m-%d %H:%M %1%2') |
119 | 153 |
120 def isodatesec(text): | 154 def isodatesec(text): |
155 """:isodatesec: Date. Returns the date in ISO 8601 format, including | |
156 seconds: "2009-08-18 13:00:13 +0200". See also the rfc3339date | |
157 filter. | |
158 """ | |
121 return util.datestr(text, '%Y-%m-%d %H:%M:%S %1%2') | 159 return util.datestr(text, '%Y-%m-%d %H:%M:%S %1%2') |
122 | 160 |
123 def indent(text, prefix): | 161 def indent(text, prefix): |
124 '''indent each non-empty line of text after first with prefix.''' | 162 '''indent each non-empty line of text after first with prefix.''' |
125 lines = text.splitlines() | 163 lines = text.splitlines() |
174 for k, v in _escapes: | 212 for k, v in _escapes: |
175 s = s.replace(k, v) | 213 s = s.replace(k, v) |
176 return ''.join(_uescape(c) for c in s) | 214 return ''.join(_uescape(c) for c in s) |
177 | 215 |
178 def localdate(text): | 216 def localdate(text): |
217 """:localdate: Date. Converts a date to local date.""" | |
179 return (text[0], util.makedate()[1]) | 218 return (text[0], util.makedate()[1]) |
180 | 219 |
181 def nonempty(str): | 220 def nonempty(str): |
221 """:nonempty: Any text. Returns '(none)' if the string is empty.""" | |
182 return str or "(none)" | 222 return str or "(none)" |
183 | 223 |
184 def obfuscate(text): | 224 def obfuscate(text): |
225 """:obfuscate: Any text. Returns the input text rendered as a sequence of | |
226 XML entities. | |
227 """ | |
185 text = unicode(text, encoding.encoding, 'replace') | 228 text = unicode(text, encoding.encoding, 'replace') |
186 return ''.join(['&#%d;' % ord(c) for c in text]) | 229 return ''.join(['&#%d;' % ord(c) for c in text]) |
187 | 230 |
188 def permissions(flags): | 231 def permissions(flags): |
189 if "l" in flags: | 232 if "l" in flags: |
191 if "x" in flags: | 234 if "x" in flags: |
192 return "-rwxr-xr-x" | 235 return "-rwxr-xr-x" |
193 return "-rw-r--r--" | 236 return "-rw-r--r--" |
194 | 237 |
195 def person(author): | 238 def person(author): |
196 '''get name of author, or else username.''' | 239 """:person: Any text. Returns the text before an email address.""" |
197 if not '@' in author: | 240 if not '@' in author: |
198 return author | 241 return author |
199 f = author.find('<') | 242 f = author.find('<') |
200 if f == -1: | 243 if f == -1: |
201 return util.shortuser(author) | 244 return util.shortuser(author) |
202 return author[:f].rstrip() | 245 return author[:f].rstrip() |
203 | 246 |
204 def rfc3339date(text): | 247 def rfc3339date(text): |
248 """:rfc3339date: Date. Returns a date using the Internet date format | |
249 specified in RFC 3339: "2009-08-18T13:00:13+02:00". | |
250 """ | |
205 return util.datestr(text, "%Y-%m-%dT%H:%M:%S%1:%2") | 251 return util.datestr(text, "%Y-%m-%dT%H:%M:%S%1:%2") |
206 | 252 |
207 def rfc822date(text): | 253 def rfc822date(text): |
254 """:rfc822date: Date. Returns a date using the same format used in email | |
255 headers: "Tue, 18 Aug 2009 13:00:13 +0200". | |
256 """ | |
208 return util.datestr(text, "%a, %d %b %Y %H:%M:%S %1%2") | 257 return util.datestr(text, "%a, %d %b %Y %H:%M:%S %1%2") |
209 | 258 |
210 def short(text): | 259 def short(text): |
260 """:short: Changeset hash. Returns the short form of a changeset hash, | |
261 i.e. a 12 hexadecimal digit string. | |
262 """ | |
211 return text[:12] | 263 return text[:12] |
212 | 264 |
213 def shortdate(text): | 265 def shortdate(text): |
266 """:shortdate: Date. Returns a date like "2006-09-18".""" | |
214 return util.shortdate(text) | 267 return util.shortdate(text) |
215 | 268 |
216 def stringescape(text): | 269 def stringescape(text): |
217 return text.encode('string_escape') | 270 return text.encode('string_escape') |
218 | 271 |
219 def stringify(thing): | 272 def stringify(thing): |
220 '''turn nested template iterator into string.''' | 273 """:stringify: Any type. Turns the value into text by converting values into |
274 text and concatenating them. | |
275 """ | |
221 if hasattr(thing, '__iter__') and not isinstance(thing, str): | 276 if hasattr(thing, '__iter__') and not isinstance(thing, str): |
222 return "".join([stringify(t) for t in thing if t is not None]) | 277 return "".join([stringify(t) for t in thing if t is not None]) |
223 return str(thing) | 278 return str(thing) |
224 | 279 |
225 def strip(text): | 280 def strip(text): |
281 """:strip: Any text. Strips all leading and trailing whitespace.""" | |
226 return text.strip() | 282 return text.strip() |
227 | 283 |
228 def stripdir(text): | 284 def stripdir(text): |
229 '''Treat the text as path and strip a directory level, if possible.''' | 285 """:stripdir: Treat the text as path and strip a directory level, if |
286 possible. For example, "foo" and "foo/bar" becomes "foo". | |
287 """ | |
230 dir = os.path.dirname(text) | 288 dir = os.path.dirname(text) |
231 if dir == "": | 289 if dir == "": |
232 return os.path.basename(text) | 290 return os.path.basename(text) |
233 else: | 291 else: |
234 return dir | 292 return dir |
235 | 293 |
236 def tabindent(text): | 294 def tabindent(text): |
295 """:tabindent: Any text. Returns the text, with every line except the | |
296 first starting with a tab character. | |
297 """ | |
237 return indent(text, '\t') | 298 return indent(text, '\t') |
238 | 299 |
239 def urlescape(text): | 300 def urlescape(text): |
301 """:urlescape: Any text. Escapes all "special" characters. For example, | |
302 "foo bar" becomes "foo%20bar". | |
303 """ | |
240 return urllib.quote(text) | 304 return urllib.quote(text) |
241 | 305 |
242 def userfilter(text): | 306 def userfilter(text): |
307 """:user: Any text. Returns the user portion of an email address.""" | |
243 return util.shortuser(text) | 308 return util.shortuser(text) |
244 | 309 |
245 def xmlescape(text): | 310 def xmlescape(text): |
246 text = (text | 311 text = (text |
247 .replace('&', '&') | 312 .replace('&', '&') |
284 "tabindent": tabindent, | 349 "tabindent": tabindent, |
285 "urlescape": urlescape, | 350 "urlescape": urlescape, |
286 "user": userfilter, | 351 "user": userfilter, |
287 "xmlescape": xmlescape, | 352 "xmlescape": xmlescape, |
288 } | 353 } |
354 | |
355 def makedoc(topic, doc): | |
356 """Generate and include templatefilters help in templating topic.""" | |
357 entries = [] | |
358 for name in sorted(filters): | |
359 text = (filters[name].__doc__ or '').rstrip() | |
360 if not text: | |
361 continue | |
362 text = gettext(text) | |
363 lines = text.splitlines() | |
364 lines[1:] = [(' ' + l.strip()) for l in lines[1:]] | |
365 entries.append('\n'.join(lines)) | |
366 entries = '\n\n'.join(entries) | |
367 doc = doc.replace('.. filtersmarker', entries) | |
368 return doc | |
369 | |
370 # tell hggettext to extract docstrings from these functions: | |
371 i18nfunctions = filters.values() |