##// END OF EJS Templates
ui: handle leading newlines/spaces/commas in configlist...
ui: handle leading newlines/spaces/commas in configlist Thanks to Greg Ward for spotting the problem introduced in 0a548640e012 and for supplying the test case.

File last commit:

r11297:d320e704 default
r11309:ef7636ef default
Show More
templatefilters.py
220 lines | 6.4 KiB | text/x-python | PythonLexer
Matt Mackall
templates: move filters to their own module...
r5976 # template-filters.py - common template expansion filters
#
# Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
templates: move filters to their own module...
r5976
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297 import cgi, re, os, time, urllib
Peter Arrenbrecht
drop unused imports
r8390 import util, encoding
Matt Mackall
templates: move filters to their own module...
r5976
Dirkjan Ochtman
templater: provide the standard template filters by default
r8360 def stringify(thing):
'''turn nested template iterator into string.'''
if hasattr(thing, '__iter__') and not isinstance(thing, str):
return "".join([stringify(t) for t in thing if t is not None])
return str(thing)
Benoit Boissinot
templatefilters: store the agescales in reverseorder directly
r10601 agescales = [("year", 3600 * 24 * 365),
("month", 3600 * 24 * 30),
Matt Mackall
templates: move filters to their own module...
r5976 ("week", 3600 * 24 * 7),
Benoit Boissinot
templatefilters: store the agescales in reverseorder directly
r10601 ("day", 3600 * 24),
("hour", 3600),
("minute", 60),
Matt Mackall
templatefilters: fix check-code warning
r10787 ("second", 1)]
Matt Mackall
templates: move filters to their own module...
r5976
def age(date):
'''turn a (timestamp, tzoff) tuple into an age string.'''
def plural(t, c):
if c == 1:
return t
return t + "s"
def fmt(t, c):
return "%d %s" % (c, plural(t, c))
now = time.time()
then = date[0]
Dirkjan Ochtman
templater: fix age filter to state the obvious on future timestamps
r7682 if then > now:
return 'in the future'
Matt Mackall
templates: move filters to their own module...
r5976 delta = max(1, int(now - then))
Dirkjan Ochtman
templater: readable dates older than 24 months revert to ISO8601 (issue1006)
r9722 if delta > agescales[0][1] * 2:
return util.shortdate(date)
Matt Mackall
templates: move filters to their own module...
r5976 for t, s in agescales:
Alejandro Santos
compat: use // for integer division
r9029 n = delta // s
Matt Mackall
templates: move filters to their own module...
r5976 if n >= 2 or s == 1:
Dirkjan Ochtman
templater: put 'ago' inside the age template filter
r9721 return '%s ago' % fmt(t, n)
Matt Mackall
templates: move filters to their own module...
r5976
para_re = None
space_re = None
def fill(text, width):
'''fill many paragraphs.'''
global para_re, space_re
if para_re is None:
para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M)
space_re = re.compile(r' +')
def findparas():
start = 0
while True:
m = para_re.search(text, start)
if not m:
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297 uctext = unicode(text[start:], encoding.encoding)
w = len(uctext)
while 0 < w and uctext[w - 1].isspace():
Matt Mackall
many, many trivial check-code fixups
r10282 w -= 1
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297 yield (uctext[:w].encode(encoding.encoding),
uctext[w:].encode(encoding.encoding))
Matt Mackall
templates: move filters to their own module...
r5976 break
yield text[start:m.start(0)], m.group(1)
start = m.end(1)
FUJIWARA Katsunori
replace Python standard textwrap by MBCS sensitive one for i18n text...
r11297 return "".join([space_re.sub(' ', util.wrap(para, width=width)) + rest
Matt Mackall
templates: move filters to their own module...
r5976 for para, rest in findparas()])
def firstline(text):
'''return the first line of text'''
try:
Nicolas Dumazet
for calls expecting bool args, pass bool instead of int...
r9136 return text.splitlines(True)[0].rstrip('\r\n')
Matt Mackall
templates: move filters to their own module...
r5976 except IndexError:
return ''
def nl2br(text):
'''replace raw newlines with xhtml line breaks.'''
return text.replace('\n', '<br/>\n')
def obfuscate(text):
Matt Mackall
move encoding bits from util to encoding...
r7948 text = unicode(text, encoding.encoding, 'replace')
Matt Mackall
templates: move filters to their own module...
r5976 return ''.join(['&#%d;' % ord(c) for c in text])
def domain(author):
'''get domain of author, or empty string if none.'''
f = author.find('@')
Matt Mackall
many, many trivial check-code fixups
r10282 if f == -1:
return ''
author = author[f + 1:]
Matt Mackall
templates: move filters to their own module...
r5976 f = author.find('>')
Matt Mackall
many, many trivial check-code fixups
r10282 if f >= 0:
author = author[:f]
Matt Mackall
templates: move filters to their own module...
r5976 return author
def person(author):
'''get name of author, or else username.'''
Matt Mackall
many, many trivial check-code fixups
r10282 if not '@' in author:
return author
Matt Mackall
templates: move filters to their own module...
r5976 f = author.find('<')
Matt Mackall
many, many trivial check-code fixups
r10282 if f == -1:
return util.shortuser(author)
Matt Mackall
templates: move filters to their own module...
r5976 return author[:f].rstrip()
def indent(text, prefix):
'''indent each non-empty line of text after first with prefix.'''
lines = text.splitlines()
num_lines = len(lines)
Nicolas Dumazet
templatefilters: indent: do not compute text.endswith('\n') in each iteration
r9387 endswithnewline = text[-1:] == '\n'
Matt Mackall
templates: move filters to their own module...
r5976 def indenter():
for i in xrange(num_lines):
l = lines[i]
if i and l.strip():
yield prefix
yield l
Nicolas Dumazet
templatefilters: indent: do not compute text.endswith('\n') in each iteration
r9387 if i < num_lines - 1 or endswithnewline:
Matt Mackall
templates: move filters to their own module...
r5976 yield '\n'
return "".join(indenter())
def permissions(flags):
if "l" in flags:
return "lrwxrwxrwx"
if "x" in flags:
return "-rwxr-xr-x"
return "-rw-r--r--"
Jesse Glick
Permit XML entities to be escaped in template output....
r6174 def xmlescape(text):
text = (text
.replace('&', '&amp;')
.replace('<', '&lt;')
.replace('>', '&gt;')
.replace('"', '&quot;')
.replace("'", '&#39;')) # &apos; invalid in HTML
return re.sub('[\x00-\x08\x0B\x0C\x0E-\x1F]', ' ', text)
Dirkjan Ochtman
add graph page to hgweb
r6691 _escapes = [
('\\', '\\\\'), ('"', '\\"'), ('\t', '\\t'), ('\n', '\\n'),
('\r', '\\r'), ('\f', '\\f'), ('\b', '\\b'),
]
Dirkjan Ochtman
templatefilters: split out jsonescape() function
r8014 def jsonescape(s):
for k, v in _escapes:
s = s.replace(k, v)
return s
Dirkjan Ochtman
add graph page to hgweb
r6691 def json(obj):
if obj is None or obj is False or obj is True:
return {None: 'null', False: 'false', True: 'true'}[obj]
elif isinstance(obj, int) or isinstance(obj, float):
return str(obj)
elif isinstance(obj, str):
Dirkjan Ochtman
templatefilters: split out jsonescape() function
r8014 return '"%s"' % jsonescape(obj)
Dirkjan Ochtman
add graph page to hgweb
r6691 elif isinstance(obj, unicode):
return json(obj.encode('utf-8'))
elif hasattr(obj, 'keys'):
out = []
for k, v in obj.iteritems():
s = '%s: %s' % (json(k), json(v))
out.append(s)
return '{' + ', '.join(out) + '}'
elif hasattr(obj, '__iter__'):
out = []
for i in obj:
out.append(json(i))
return '[' + ', '.join(out) + ']'
else:
raise TypeError('cannot encode type %s' % obj.__class__.__name__)
Aleix Conchillo Flaque
templatefilters: add new stripdir filter...
r8158 def stripdir(text):
'''Treat the text as path and strip a directory level, if possible.'''
dir = os.path.dirname(text)
if dir == "":
return os.path.basename(text)
else:
return dir
Rocco Rutte
templatefilters: add "nonempty" template filter...
r8234 def nonempty(str):
Peter Arrenbrecht
indentation cleanup
r8389 return str or "(none)"
Rocco Rutte
templatefilters: add "nonempty" template filter...
r8234
Matt Mackall
templates: move filters to their own module...
r5976 filters = {
"addbreaks": nl2br,
"basename": os.path.basename,
Aleix Conchillo Flaque
templatefilters: add new stripdir filter...
r8158 "stripdir": stripdir,
Matt Mackall
templates: move filters to their own module...
r5976 "age": age,
"date": lambda x: util.datestr(x),
"domain": domain,
"email": util.email,
"escape": lambda x: cgi.escape(x, True),
"fill68": lambda x: fill(x, width=68),
"fill76": lambda x: fill(x, width=76),
"firstline": firstline,
"tabindent": lambda x: indent(x, '\t'),
Matt Mackall
dates: improve timezone handling...
r6229 "hgdate": lambda x: "%d %d" % x,
"isodate": lambda x: util.datestr(x, '%Y-%m-%d %H:%M %1%2'),
Giorgos Keramidas
Add an {isodatesec} template, to show seconds too.
r6319 "isodatesec": lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2'),
Dirkjan Ochtman
templatefilters: split out jsonescape() function
r8014 "json": json,
"jsonescape": jsonescape,
Henrik Stuart
templatefilters: add filter to convert date to local date (issue1674)...
r8591 "localdate": lambda x: (x[0], util.makedate()[1]),
Rocco Rutte
templatefilters: add "nonempty" template filter...
r8234 "nonempty": nonempty,
Matt Mackall
templates: move filters to their own module...
r5976 "obfuscate": obfuscate,
"permissions": permissions,
"person": person,
Matt Mackall
dates: improve timezone handling...
r6229 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S %1%2"),
"rfc3339date": lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S%1:%2"),
Matt Mackall
templates: move filters to their own module...
r5976 "short": lambda x: x[:12],
Thomas Arendsen Hein
Make annotae/grep print short dates with -q/--quiet....
r6134 "shortdate": util.shortdate,
Dirkjan Ochtman
templater: provide the standard template filters by default
r8360 "stringify": stringify,
Matt Mackall
templates: move filters to their own module...
r5976 "strip": lambda x: x.strip(),
"urlescape": lambda x: urllib.quote(x),
"user": lambda x: util.shortuser(x),
"stringescape": lambda x: x.encode('string_escape'),
Jesse Glick
Permit XML entities to be escaped in template output....
r6174 "xmlescape": xmlescape,
Dirkjan Ochtman
add graph page to hgweb
r6691 }