Mercurial > public > mercurial-scm > hg
comparison mercurial/templatefilters.py @ 43077:687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Done with
python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py')
black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**')
# skip-blame mass-reformatting only
Differential Revision: https://phab.mercurial-scm.org/D6972
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:48:39 -0400 |
parents | 2372284d9457 |
children | bbcbb82e3589 |
comparison
equal
deleted
inserted
replaced
43076:2372284d9457 | 43077:687b865b95ad |
---|---|
41 filters = {} | 41 filters = {} |
42 | 42 |
43 templatefilter = registrar.templatefilter(filters) | 43 templatefilter = registrar.templatefilter(filters) |
44 | 44 |
45 | 45 |
46 @templatefilter('addbreaks', intype=bytes) | 46 @templatefilter(b'addbreaks', intype=bytes) |
47 def addbreaks(text): | 47 def addbreaks(text): |
48 """Any text. Add an XHTML "<br />" tag before the end of | 48 """Any text. Add an XHTML "<br />" tag before the end of |
49 every line except the last. | 49 every line except the last. |
50 """ | 50 """ |
51 return text.replace('\n', '<br/>\n') | 51 return text.replace(b'\n', b'<br/>\n') |
52 | 52 |
53 | 53 |
54 agescales = [ | 54 agescales = [ |
55 ("year", 3600 * 24 * 365, 'Y'), | 55 (b"year", 3600 * 24 * 365, b'Y'), |
56 ("month", 3600 * 24 * 30, 'M'), | 56 (b"month", 3600 * 24 * 30, b'M'), |
57 ("week", 3600 * 24 * 7, 'W'), | 57 (b"week", 3600 * 24 * 7, b'W'), |
58 ("day", 3600 * 24, 'd'), | 58 (b"day", 3600 * 24, b'd'), |
59 ("hour", 3600, 'h'), | 59 (b"hour", 3600, b'h'), |
60 ("minute", 60, 'm'), | 60 (b"minute", 60, b'm'), |
61 ("second", 1, 's'), | 61 (b"second", 1, b's'), |
62 ] | 62 ] |
63 | 63 |
64 | 64 |
65 @templatefilter('age', intype=templateutil.date) | 65 @templatefilter(b'age', intype=templateutil.date) |
66 def age(date, abbrev=False): | 66 def age(date, abbrev=False): |
67 """Date. Returns a human-readable date/time difference between the | 67 """Date. Returns a human-readable date/time difference between the |
68 given date/time and the current date/time. | 68 given date/time and the current date/time. |
69 """ | 69 """ |
70 | 70 |
71 def plural(t, c): | 71 def plural(t, c): |
72 if c == 1: | 72 if c == 1: |
73 return t | 73 return t |
74 return t + "s" | 74 return t + b"s" |
75 | 75 |
76 def fmt(t, c, a): | 76 def fmt(t, c, a): |
77 if abbrev: | 77 if abbrev: |
78 return "%d%s" % (c, a) | 78 return b"%d%s" % (c, a) |
79 return "%d %s" % (c, plural(t, c)) | 79 return b"%d %s" % (c, plural(t, c)) |
80 | 80 |
81 now = time.time() | 81 now = time.time() |
82 then = date[0] | 82 then = date[0] |
83 future = False | 83 future = False |
84 if then > now: | 84 if then > now: |
85 future = True | 85 future = True |
86 delta = max(1, int(then - now)) | 86 delta = max(1, int(then - now)) |
87 if delta > agescales[0][1] * 30: | 87 if delta > agescales[0][1] * 30: |
88 return 'in the distant future' | 88 return b'in the distant future' |
89 else: | 89 else: |
90 delta = max(1, int(now - then)) | 90 delta = max(1, int(now - then)) |
91 if delta > agescales[0][1] * 2: | 91 if delta > agescales[0][1] * 2: |
92 return dateutil.shortdate(date) | 92 return dateutil.shortdate(date) |
93 | 93 |
94 for t, s, a in agescales: | 94 for t, s, a in agescales: |
95 n = delta // s | 95 n = delta // s |
96 if n >= 2 or s == 1: | 96 if n >= 2 or s == 1: |
97 if future: | 97 if future: |
98 return '%s from now' % fmt(t, n, a) | 98 return b'%s from now' % fmt(t, n, a) |
99 return '%s ago' % fmt(t, n, a) | 99 return b'%s ago' % fmt(t, n, a) |
100 | 100 |
101 | 101 |
102 @templatefilter('basename', intype=bytes) | 102 @templatefilter(b'basename', intype=bytes) |
103 def basename(path): | 103 def basename(path): |
104 """Any text. Treats the text as a path, and returns the last | 104 """Any text. Treats the text as a path, and returns the last |
105 component of the path after splitting by the path separator. | 105 component of the path after splitting by the path separator. |
106 For example, "foo/bar/baz" becomes "baz" and "foo/bar//" becomes "". | 106 For example, "foo/bar/baz" becomes "baz" and "foo/bar//" becomes "". |
107 """ | 107 """ |
108 return os.path.basename(path) | 108 return os.path.basename(path) |
109 | 109 |
110 | 110 |
111 @templatefilter('cbor') | 111 @templatefilter(b'cbor') |
112 def cbor(obj): | 112 def cbor(obj): |
113 """Any object. Serializes the object to CBOR bytes.""" | 113 """Any object. Serializes the object to CBOR bytes.""" |
114 return b''.join(cborutil.streamencode(obj)) | 114 return b''.join(cborutil.streamencode(obj)) |
115 | 115 |
116 | 116 |
117 @templatefilter('commondir') | 117 @templatefilter(b'commondir') |
118 def commondir(filelist): | 118 def commondir(filelist): |
119 """List of text. Treats each list item as file name with / | 119 """List of text. Treats each list item as file name with / |
120 as path separator and returns the longest common directory | 120 as path separator and returns the longest common directory |
121 prefix shared by all list items. | 121 prefix shared by all list items. |
122 Returns the empty string if no common prefix exists. | 122 Returns the empty string if no common prefix exists. |
140 return a[:i] | 140 return a[:i] |
141 return a | 141 return a |
142 | 142 |
143 try: | 143 try: |
144 if not filelist: | 144 if not filelist: |
145 return "" | 145 return b"" |
146 dirlist = [f.lstrip('/').split('/')[:-1] for f in filelist] | 146 dirlist = [f.lstrip(b'/').split(b'/')[:-1] for f in filelist] |
147 if len(dirlist) == 1: | 147 if len(dirlist) == 1: |
148 return '/'.join(dirlist[0]) | 148 return b'/'.join(dirlist[0]) |
149 a = min(dirlist) | 149 a = min(dirlist) |
150 b = max(dirlist) | 150 b = max(dirlist) |
151 # The common prefix of a and b is shared with all | 151 # The common prefix of a and b is shared with all |
152 # elements of the list since Python sorts lexicographical | 152 # elements of the list since Python sorts lexicographical |
153 # and [1, x] after [1]. | 153 # and [1, x] after [1]. |
154 return '/'.join(common(a, b)) | 154 return b'/'.join(common(a, b)) |
155 except TypeError: | 155 except TypeError: |
156 raise error.ParseError(_('argument is not a list of text')) | 156 raise error.ParseError(_(b'argument is not a list of text')) |
157 | 157 |
158 | 158 |
159 @templatefilter('count') | 159 @templatefilter(b'count') |
160 def count(i): | 160 def count(i): |
161 """List or text. Returns the length as an integer.""" | 161 """List or text. Returns the length as an integer.""" |
162 try: | 162 try: |
163 return len(i) | 163 return len(i) |
164 except TypeError: | 164 except TypeError: |
165 raise error.ParseError(_('not countable')) | 165 raise error.ParseError(_(b'not countable')) |
166 | 166 |
167 | 167 |
168 @templatefilter('dirname', intype=bytes) | 168 @templatefilter(b'dirname', intype=bytes) |
169 def dirname(path): | 169 def dirname(path): |
170 """Any text. Treats the text as a path, and strips the last | 170 """Any text. Treats the text as a path, and strips the last |
171 component of the path after splitting by the path separator. | 171 component of the path after splitting by the path separator. |
172 """ | 172 """ |
173 return os.path.dirname(path) | 173 return os.path.dirname(path) |
174 | 174 |
175 | 175 |
176 @templatefilter('domain', intype=bytes) | 176 @templatefilter(b'domain', intype=bytes) |
177 def domain(author): | 177 def domain(author): |
178 """Any text. Finds the first string that looks like an email | 178 """Any text. Finds the first string that looks like an email |
179 address, and extracts just the domain component. Example: ``User | 179 address, and extracts just the domain component. Example: ``User |
180 <user@example.com>`` becomes ``example.com``. | 180 <user@example.com>`` becomes ``example.com``. |
181 """ | 181 """ |
182 f = author.find('@') | 182 f = author.find(b'@') |
183 if f == -1: | 183 if f == -1: |
184 return '' | 184 return b'' |
185 author = author[f + 1 :] | 185 author = author[f + 1 :] |
186 f = author.find('>') | 186 f = author.find(b'>') |
187 if f >= 0: | 187 if f >= 0: |
188 author = author[:f] | 188 author = author[:f] |
189 return author | 189 return author |
190 | 190 |
191 | 191 |
192 @templatefilter('email', intype=bytes) | 192 @templatefilter(b'email', intype=bytes) |
193 def email(text): | 193 def email(text): |
194 """Any text. Extracts the first string that looks like an email | 194 """Any text. Extracts the first string that looks like an email |
195 address. Example: ``User <user@example.com>`` becomes | 195 address. Example: ``User <user@example.com>`` becomes |
196 ``user@example.com``. | 196 ``user@example.com``. |
197 """ | 197 """ |
198 return stringutil.email(text) | 198 return stringutil.email(text) |
199 | 199 |
200 | 200 |
201 @templatefilter('escape', intype=bytes) | 201 @templatefilter(b'escape', intype=bytes) |
202 def escape(text): | 202 def escape(text): |
203 """Any text. Replaces the special XML/XHTML characters "&", "<" | 203 """Any text. Replaces the special XML/XHTML characters "&", "<" |
204 and ">" with XML entities, and filters out NUL characters. | 204 and ">" with XML entities, and filters out NUL characters. |
205 """ | 205 """ |
206 return url.escape(text.replace('\0', ''), True) | 206 return url.escape(text.replace(b'\0', b''), True) |
207 | 207 |
208 | 208 |
209 para_re = None | 209 para_re = None |
210 space_re = None | 210 space_re = None |
211 | 211 |
212 | 212 |
213 def fill(text, width, initindent='', hangindent=''): | 213 def fill(text, width, initindent=b'', hangindent=b''): |
214 '''fill many paragraphs with optional indentation.''' | 214 '''fill many paragraphs with optional indentation.''' |
215 global para_re, space_re | 215 global para_re, space_re |
216 if para_re is None: | 216 if para_re is None: |
217 para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M) | 217 para_re = re.compile(b'(\n\n|\n\\s*[-*]\\s*)', re.M) |
218 space_re = re.compile(br' +') | 218 space_re = re.compile(br' +') |
219 | 219 |
220 def findparas(): | 220 def findparas(): |
221 start = 0 | 221 start = 0 |
222 while True: | 222 while True: |
232 ) | 232 ) |
233 break | 233 break |
234 yield text[start : m.start(0)], m.group(1) | 234 yield text[start : m.start(0)], m.group(1) |
235 start = m.end(1) | 235 start = m.end(1) |
236 | 236 |
237 return "".join( | 237 return b"".join( |
238 [ | 238 [ |
239 stringutil.wrap( | 239 stringutil.wrap( |
240 space_re.sub(' ', stringutil.wrap(para, width)), | 240 space_re.sub(b' ', stringutil.wrap(para, width)), |
241 width, | 241 width, |
242 initindent, | 242 initindent, |
243 hangindent, | 243 hangindent, |
244 ) | 244 ) |
245 + rest | 245 + rest |
246 for para, rest in findparas() | 246 for para, rest in findparas() |
247 ] | 247 ] |
248 ) | 248 ) |
249 | 249 |
250 | 250 |
251 @templatefilter('fill68', intype=bytes) | 251 @templatefilter(b'fill68', intype=bytes) |
252 def fill68(text): | 252 def fill68(text): |
253 """Any text. Wraps the text to fit in 68 columns.""" | 253 """Any text. Wraps the text to fit in 68 columns.""" |
254 return fill(text, 68) | 254 return fill(text, 68) |
255 | 255 |
256 | 256 |
257 @templatefilter('fill76', intype=bytes) | 257 @templatefilter(b'fill76', intype=bytes) |
258 def fill76(text): | 258 def fill76(text): |
259 """Any text. Wraps the text to fit in 76 columns.""" | 259 """Any text. Wraps the text to fit in 76 columns.""" |
260 return fill(text, 76) | 260 return fill(text, 76) |
261 | 261 |
262 | 262 |
263 @templatefilter('firstline', intype=bytes) | 263 @templatefilter(b'firstline', intype=bytes) |
264 def firstline(text): | 264 def firstline(text): |
265 """Any text. Returns the first line of text.""" | 265 """Any text. Returns the first line of text.""" |
266 try: | 266 try: |
267 return text.splitlines(True)[0].rstrip('\r\n') | 267 return text.splitlines(True)[0].rstrip(b'\r\n') |
268 except IndexError: | 268 except IndexError: |
269 return '' | 269 return b'' |
270 | 270 |
271 | 271 |
272 @templatefilter('hex', intype=bytes) | 272 @templatefilter(b'hex', intype=bytes) |
273 def hexfilter(text): | 273 def hexfilter(text): |
274 """Any text. Convert a binary Mercurial node identifier into | 274 """Any text. Convert a binary Mercurial node identifier into |
275 its long hexadecimal representation. | 275 its long hexadecimal representation. |
276 """ | 276 """ |
277 return node.hex(text) | 277 return node.hex(text) |
278 | 278 |
279 | 279 |
280 @templatefilter('hgdate', intype=templateutil.date) | 280 @templatefilter(b'hgdate', intype=templateutil.date) |
281 def hgdate(text): | 281 def hgdate(text): |
282 """Date. Returns the date as a pair of numbers: "1157407993 | 282 """Date. Returns the date as a pair of numbers: "1157407993 |
283 25200" (Unix timestamp, timezone offset). | 283 25200" (Unix timestamp, timezone offset). |
284 """ | 284 """ |
285 return "%d %d" % text | 285 return b"%d %d" % text |
286 | 286 |
287 | 287 |
288 @templatefilter('isodate', intype=templateutil.date) | 288 @templatefilter(b'isodate', intype=templateutil.date) |
289 def isodate(text): | 289 def isodate(text): |
290 """Date. Returns the date in ISO 8601 format: "2009-08-18 13:00 | 290 """Date. Returns the date in ISO 8601 format: "2009-08-18 13:00 |
291 +0200". | 291 +0200". |
292 """ | 292 """ |
293 return dateutil.datestr(text, '%Y-%m-%d %H:%M %1%2') | 293 return dateutil.datestr(text, b'%Y-%m-%d %H:%M %1%2') |
294 | 294 |
295 | 295 |
296 @templatefilter('isodatesec', intype=templateutil.date) | 296 @templatefilter(b'isodatesec', intype=templateutil.date) |
297 def isodatesec(text): | 297 def isodatesec(text): |
298 """Date. Returns the date in ISO 8601 format, including | 298 """Date. Returns the date in ISO 8601 format, including |
299 seconds: "2009-08-18 13:00:13 +0200". See also the rfc3339date | 299 seconds: "2009-08-18 13:00:13 +0200". See also the rfc3339date |
300 filter. | 300 filter. |
301 """ | 301 """ |
302 return dateutil.datestr(text, '%Y-%m-%d %H:%M:%S %1%2') | 302 return dateutil.datestr(text, b'%Y-%m-%d %H:%M:%S %1%2') |
303 | 303 |
304 | 304 |
305 def indent(text, prefix): | 305 def indent(text, prefix): |
306 '''indent each non-empty line of text after first with prefix.''' | 306 '''indent each non-empty line of text after first with prefix.''' |
307 lines = text.splitlines() | 307 lines = text.splitlines() |
308 num_lines = len(lines) | 308 num_lines = len(lines) |
309 endswithnewline = text[-1:] == '\n' | 309 endswithnewline = text[-1:] == b'\n' |
310 | 310 |
311 def indenter(): | 311 def indenter(): |
312 for i in pycompat.xrange(num_lines): | 312 for i in pycompat.xrange(num_lines): |
313 l = lines[i] | 313 l = lines[i] |
314 if i and l.strip(): | 314 if i and l.strip(): |
315 yield prefix | 315 yield prefix |
316 yield l | 316 yield l |
317 if i < num_lines - 1 or endswithnewline: | 317 if i < num_lines - 1 or endswithnewline: |
318 yield '\n' | 318 yield b'\n' |
319 | 319 |
320 return "".join(indenter()) | 320 return b"".join(indenter()) |
321 | 321 |
322 | 322 |
323 @templatefilter('json') | 323 @templatefilter(b'json') |
324 def json(obj, paranoid=True): | 324 def json(obj, paranoid=True): |
325 """Any object. Serializes the object to a JSON formatted text.""" | 325 """Any object. Serializes the object to a JSON formatted text.""" |
326 if obj is None: | 326 if obj is None: |
327 return 'null' | 327 return b'null' |
328 elif obj is False: | 328 elif obj is False: |
329 return 'false' | 329 return b'false' |
330 elif obj is True: | 330 elif obj is True: |
331 return 'true' | 331 return b'true' |
332 elif isinstance(obj, (int, long, float)): | 332 elif isinstance(obj, (int, long, float)): |
333 return pycompat.bytestr(obj) | 333 return pycompat.bytestr(obj) |
334 elif isinstance(obj, bytes): | 334 elif isinstance(obj, bytes): |
335 return '"%s"' % encoding.jsonescape(obj, paranoid=paranoid) | 335 return b'"%s"' % encoding.jsonescape(obj, paranoid=paranoid) |
336 elif isinstance(obj, type(u'')): | 336 elif isinstance(obj, type(u'')): |
337 raise error.ProgrammingError( | 337 raise error.ProgrammingError( |
338 'Mercurial only does output with bytes: %r' % obj | 338 b'Mercurial only does output with bytes: %r' % obj |
339 ) | 339 ) |
340 elif util.safehasattr(obj, 'keys'): | 340 elif util.safehasattr(obj, b'keys'): |
341 out = [ | 341 out = [ |
342 '"%s": %s' | 342 b'"%s": %s' |
343 % (encoding.jsonescape(k, paranoid=paranoid), json(v, paranoid)) | 343 % (encoding.jsonescape(k, paranoid=paranoid), json(v, paranoid)) |
344 for k, v in sorted(obj.iteritems()) | 344 for k, v in sorted(obj.iteritems()) |
345 ] | 345 ] |
346 return '{' + ', '.join(out) + '}' | 346 return b'{' + b', '.join(out) + b'}' |
347 elif util.safehasattr(obj, '__iter__'): | 347 elif util.safehasattr(obj, b'__iter__'): |
348 out = [json(i, paranoid) for i in obj] | 348 out = [json(i, paranoid) for i in obj] |
349 return '[' + ', '.join(out) + ']' | 349 return b'[' + b', '.join(out) + b']' |
350 raise error.ProgrammingError('cannot encode %r' % obj) | 350 raise error.ProgrammingError(b'cannot encode %r' % obj) |
351 | 351 |
352 | 352 |
353 @templatefilter('lower', intype=bytes) | 353 @templatefilter(b'lower', intype=bytes) |
354 def lower(text): | 354 def lower(text): |
355 """Any text. Converts the text to lowercase.""" | 355 """Any text. Converts the text to lowercase.""" |
356 return encoding.lower(text) | 356 return encoding.lower(text) |
357 | 357 |
358 | 358 |
359 @templatefilter('nonempty', intype=bytes) | 359 @templatefilter(b'nonempty', intype=bytes) |
360 def nonempty(text): | 360 def nonempty(text): |
361 """Any text. Returns '(none)' if the string is empty.""" | 361 """Any text. Returns '(none)' if the string is empty.""" |
362 return text or "(none)" | 362 return text or b"(none)" |
363 | 363 |
364 | 364 |
365 @templatefilter('obfuscate', intype=bytes) | 365 @templatefilter(b'obfuscate', intype=bytes) |
366 def obfuscate(text): | 366 def obfuscate(text): |
367 """Any text. Returns the input text rendered as a sequence of | 367 """Any text. Returns the input text rendered as a sequence of |
368 XML entities. | 368 XML entities. |
369 """ | 369 """ |
370 text = unicode(text, pycompat.sysstr(encoding.encoding), r'replace') | 370 text = unicode(text, pycompat.sysstr(encoding.encoding), r'replace') |
371 return ''.join(['&#%d;' % ord(c) for c in text]) | 371 return b''.join([b'&#%d;' % ord(c) for c in text]) |
372 | 372 |
373 | 373 |
374 @templatefilter('permissions', intype=bytes) | 374 @templatefilter(b'permissions', intype=bytes) |
375 def permissions(flags): | 375 def permissions(flags): |
376 if "l" in flags: | 376 if b"l" in flags: |
377 return "lrwxrwxrwx" | 377 return b"lrwxrwxrwx" |
378 if "x" in flags: | 378 if b"x" in flags: |
379 return "-rwxr-xr-x" | 379 return b"-rwxr-xr-x" |
380 return "-rw-r--r--" | 380 return b"-rw-r--r--" |
381 | 381 |
382 | 382 |
383 @templatefilter('person', intype=bytes) | 383 @templatefilter(b'person', intype=bytes) |
384 def person(author): | 384 def person(author): |
385 """Any text. Returns the name before an email address, | 385 """Any text. Returns the name before an email address, |
386 interpreting it as per RFC 5322. | 386 interpreting it as per RFC 5322. |
387 """ | 387 """ |
388 return stringutil.person(author) | 388 return stringutil.person(author) |
389 | 389 |
390 | 390 |
391 @templatefilter('revescape', intype=bytes) | 391 @templatefilter(b'revescape', intype=bytes) |
392 def revescape(text): | 392 def revescape(text): |
393 """Any text. Escapes all "special" characters, except @. | 393 """Any text. Escapes all "special" characters, except @. |
394 Forward slashes are escaped twice to prevent web servers from prematurely | 394 Forward slashes are escaped twice to prevent web servers from prematurely |
395 unescaping them. For example, "@foo bar/baz" becomes "@foo%20bar%252Fbaz". | 395 unescaping them. For example, "@foo bar/baz" becomes "@foo%20bar%252Fbaz". |
396 """ | 396 """ |
397 return urlreq.quote(text, safe='/@').replace('/', '%252F') | 397 return urlreq.quote(text, safe=b'/@').replace(b'/', b'%252F') |
398 | 398 |
399 | 399 |
400 @templatefilter('rfc3339date', intype=templateutil.date) | 400 @templatefilter(b'rfc3339date', intype=templateutil.date) |
401 def rfc3339date(text): | 401 def rfc3339date(text): |
402 """Date. Returns a date using the Internet date format | 402 """Date. Returns a date using the Internet date format |
403 specified in RFC 3339: "2009-08-18T13:00:13+02:00". | 403 specified in RFC 3339: "2009-08-18T13:00:13+02:00". |
404 """ | 404 """ |
405 return dateutil.datestr(text, "%Y-%m-%dT%H:%M:%S%1:%2") | 405 return dateutil.datestr(text, b"%Y-%m-%dT%H:%M:%S%1:%2") |
406 | 406 |
407 | 407 |
408 @templatefilter('rfc822date', intype=templateutil.date) | 408 @templatefilter(b'rfc822date', intype=templateutil.date) |
409 def rfc822date(text): | 409 def rfc822date(text): |
410 """Date. Returns a date using the same format used in email | 410 """Date. Returns a date using the same format used in email |
411 headers: "Tue, 18 Aug 2009 13:00:13 +0200". | 411 headers: "Tue, 18 Aug 2009 13:00:13 +0200". |
412 """ | 412 """ |
413 return dateutil.datestr(text, "%a, %d %b %Y %H:%M:%S %1%2") | 413 return dateutil.datestr(text, b"%a, %d %b %Y %H:%M:%S %1%2") |
414 | 414 |
415 | 415 |
416 @templatefilter('short', intype=bytes) | 416 @templatefilter(b'short', intype=bytes) |
417 def short(text): | 417 def short(text): |
418 """Changeset hash. Returns the short form of a changeset hash, | 418 """Changeset hash. Returns the short form of a changeset hash, |
419 i.e. a 12 hexadecimal digit string. | 419 i.e. a 12 hexadecimal digit string. |
420 """ | 420 """ |
421 return text[:12] | 421 return text[:12] |
422 | 422 |
423 | 423 |
424 @templatefilter('shortbisect', intype=bytes) | 424 @templatefilter(b'shortbisect', intype=bytes) |
425 def shortbisect(label): | 425 def shortbisect(label): |
426 """Any text. Treats `label` as a bisection status, and | 426 """Any text. Treats `label` as a bisection status, and |
427 returns a single-character representing the status (G: good, B: bad, | 427 returns a single-character representing the status (G: good, B: bad, |
428 S: skipped, U: untested, I: ignored). Returns single space if `text` | 428 S: skipped, U: untested, I: ignored). Returns single space if `text` |
429 is not a valid bisection status. | 429 is not a valid bisection status. |
430 """ | 430 """ |
431 if label: | 431 if label: |
432 return label[0:1].upper() | 432 return label[0:1].upper() |
433 return ' ' | 433 return b' ' |
434 | 434 |
435 | 435 |
436 @templatefilter('shortdate', intype=templateutil.date) | 436 @templatefilter(b'shortdate', intype=templateutil.date) |
437 def shortdate(text): | 437 def shortdate(text): |
438 """Date. Returns a date like "2006-09-18".""" | 438 """Date. Returns a date like "2006-09-18".""" |
439 return dateutil.shortdate(text) | 439 return dateutil.shortdate(text) |
440 | 440 |
441 | 441 |
442 @templatefilter('slashpath', intype=bytes) | 442 @templatefilter(b'slashpath', intype=bytes) |
443 def slashpath(path): | 443 def slashpath(path): |
444 """Any text. Replaces the native path separator with slash.""" | 444 """Any text. Replaces the native path separator with slash.""" |
445 return util.pconvert(path) | 445 return util.pconvert(path) |
446 | 446 |
447 | 447 |
448 @templatefilter('splitlines', intype=bytes) | 448 @templatefilter(b'splitlines', intype=bytes) |
449 def splitlines(text): | 449 def splitlines(text): |
450 """Any text. Split text into a list of lines.""" | 450 """Any text. Split text into a list of lines.""" |
451 return templateutil.hybridlist(text.splitlines(), name='line') | 451 return templateutil.hybridlist(text.splitlines(), name=b'line') |
452 | 452 |
453 | 453 |
454 @templatefilter('stringescape', intype=bytes) | 454 @templatefilter(b'stringescape', intype=bytes) |
455 def stringescape(text): | 455 def stringescape(text): |
456 return stringutil.escapestr(text) | 456 return stringutil.escapestr(text) |
457 | 457 |
458 | 458 |
459 @templatefilter('stringify', intype=bytes) | 459 @templatefilter(b'stringify', intype=bytes) |
460 def stringify(thing): | 460 def stringify(thing): |
461 """Any type. Turns the value into text by converting values into | 461 """Any type. Turns the value into text by converting values into |
462 text and concatenating them. | 462 text and concatenating them. |
463 """ | 463 """ |
464 return thing # coerced by the intype | 464 return thing # coerced by the intype |
465 | 465 |
466 | 466 |
467 @templatefilter('stripdir', intype=bytes) | 467 @templatefilter(b'stripdir', intype=bytes) |
468 def stripdir(text): | 468 def stripdir(text): |
469 """Treat the text as path and strip a directory level, if | 469 """Treat the text as path and strip a directory level, if |
470 possible. For example, "foo" and "foo/bar" becomes "foo". | 470 possible. For example, "foo" and "foo/bar" becomes "foo". |
471 """ | 471 """ |
472 dir = os.path.dirname(text) | 472 dir = os.path.dirname(text) |
473 if dir == "": | 473 if dir == b"": |
474 return os.path.basename(text) | 474 return os.path.basename(text) |
475 else: | 475 else: |
476 return dir | 476 return dir |
477 | 477 |
478 | 478 |
479 @templatefilter('tabindent', intype=bytes) | 479 @templatefilter(b'tabindent', intype=bytes) |
480 def tabindent(text): | 480 def tabindent(text): |
481 """Any text. Returns the text, with every non-empty line | 481 """Any text. Returns the text, with every non-empty line |
482 except the first starting with a tab character. | 482 except the first starting with a tab character. |
483 """ | 483 """ |
484 return indent(text, '\t') | 484 return indent(text, b'\t') |
485 | 485 |
486 | 486 |
487 @templatefilter('upper', intype=bytes) | 487 @templatefilter(b'upper', intype=bytes) |
488 def upper(text): | 488 def upper(text): |
489 """Any text. Converts the text to uppercase.""" | 489 """Any text. Converts the text to uppercase.""" |
490 return encoding.upper(text) | 490 return encoding.upper(text) |
491 | 491 |
492 | 492 |
493 @templatefilter('urlescape', intype=bytes) | 493 @templatefilter(b'urlescape', intype=bytes) |
494 def urlescape(text): | 494 def urlescape(text): |
495 """Any text. Escapes all "special" characters. For example, | 495 """Any text. Escapes all "special" characters. For example, |
496 "foo bar" becomes "foo%20bar". | 496 "foo bar" becomes "foo%20bar". |
497 """ | 497 """ |
498 return urlreq.quote(text) | 498 return urlreq.quote(text) |
499 | 499 |
500 | 500 |
501 @templatefilter('user', intype=bytes) | 501 @templatefilter(b'user', intype=bytes) |
502 def userfilter(text): | 502 def userfilter(text): |
503 """Any text. Returns a short representation of a user name or email | 503 """Any text. Returns a short representation of a user name or email |
504 address.""" | 504 address.""" |
505 return stringutil.shortuser(text) | 505 return stringutil.shortuser(text) |
506 | 506 |
507 | 507 |
508 @templatefilter('emailuser', intype=bytes) | 508 @templatefilter(b'emailuser', intype=bytes) |
509 def emailuser(text): | 509 def emailuser(text): |
510 """Any text. Returns the user portion of an email address.""" | 510 """Any text. Returns the user portion of an email address.""" |
511 return stringutil.emailuser(text) | 511 return stringutil.emailuser(text) |
512 | 512 |
513 | 513 |
514 @templatefilter('utf8', intype=bytes) | 514 @templatefilter(b'utf8', intype=bytes) |
515 def utf8(text): | 515 def utf8(text): |
516 """Any text. Converts from the local character encoding to UTF-8.""" | 516 """Any text. Converts from the local character encoding to UTF-8.""" |
517 return encoding.fromlocal(text) | 517 return encoding.fromlocal(text) |
518 | 518 |
519 | 519 |
520 @templatefilter('xmlescape', intype=bytes) | 520 @templatefilter(b'xmlescape', intype=bytes) |
521 def xmlescape(text): | 521 def xmlescape(text): |
522 text = ( | 522 text = ( |
523 text.replace('&', '&') | 523 text.replace(b'&', b'&') |
524 .replace('<', '<') | 524 .replace(b'<', b'<') |
525 .replace('>', '>') | 525 .replace(b'>', b'>') |
526 .replace('"', '"') | 526 .replace(b'"', b'"') |
527 .replace("'", ''') | 527 .replace(b"'", b''') |
528 ) # ' invalid in HTML | 528 ) # ' invalid in HTML |
529 return re.sub('[\x00-\x08\x0B\x0C\x0E-\x1F]', ' ', text) | 529 return re.sub(b'[\x00-\x08\x0B\x0C\x0E-\x1F]', b' ', text) |
530 | 530 |
531 | 531 |
532 def websub(text, websubtable): | 532 def websub(text, websubtable): |
533 """:websub: Any text. Only applies to hgweb. Applies the regular | 533 """:websub: Any text. Only applies to hgweb. Applies the regular |
534 expression replacements defined in the websub section. | 534 expression replacements defined in the websub section. |