mercurial/templatefilters.py
author Adrian Buehlmann <adrian@cadifra.com>
Sun, 21 Nov 2010 11:52:27 +0100
changeset 13026 53391819f195
parent 12371 48a4acd1ccf1
child 13586 57150dc5a9c7
permissions -rw-r--r--
check-code: catch Python 'is' comparing number or string literals The Python 'is' operator compares object identity, so it should definitely not be applied to string or number literals, which Python implementations are free to represent with a temporary object. This should catch the following kinds of bogus expressions (examples): x is 'foo' x is not 'foo' x is "bar" x is not "bar" x is 42 x is not 42 x is -36 x is not -36 As originally proposed by Martin Geisler, amended with catching negative numbers.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     1
# template-filters.py - common template expansion filters
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     2
#
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     3
# Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     4
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8158
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9722
diff changeset
     6
# GNU General Public License version 2 or any later version.
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     7
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10787
diff changeset
     8
import cgi, re, os, time, urllib
12371
48a4acd1ccf1 templater: add hex filter.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11891
diff changeset
     9
import encoding, node, util
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    10
8360
acc202b71619 templater: provide the standard template filters by default
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8234
diff changeset
    11
def stringify(thing):
acc202b71619 templater: provide the standard template filters by default
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8234
diff changeset
    12
    '''turn nested template iterator into string.'''
acc202b71619 templater: provide the standard template filters by default
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8234
diff changeset
    13
    if hasattr(thing, '__iter__') and not isinstance(thing, str):
acc202b71619 templater: provide the standard template filters by default
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8234
diff changeset
    14
        return "".join([stringify(t) for t in thing if t is not None])
acc202b71619 templater: provide the standard template filters by default
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8234
diff changeset
    15
    return str(thing)
acc202b71619 templater: provide the standard template filters by default
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8234
diff changeset
    16
10601
b98b6a7363ae templatefilters: store the agescales in reverseorder directly
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
    17
agescales = [("year", 3600 * 24 * 365),
b98b6a7363ae templatefilters: store the agescales in reverseorder directly
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
    18
             ("month", 3600 * 24 * 30),
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    19
             ("week", 3600 * 24 * 7),
10601
b98b6a7363ae templatefilters: store the agescales in reverseorder directly
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
    20
             ("day", 3600 * 24),
b98b6a7363ae templatefilters: store the agescales in reverseorder directly
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
    21
             ("hour", 3600),
b98b6a7363ae templatefilters: store the agescales in reverseorder directly
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10282
diff changeset
    22
             ("minute", 60),
10787
5974123d0339 templatefilters: fix check-code warning
Matt Mackall <mpm@selenic.com>
parents: 10601
diff changeset
    23
             ("second", 1)]
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    24
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    25
def age(date):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    26
    '''turn a (timestamp, tzoff) tuple into an age string.'''
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    27
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    28
    def plural(t, c):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    29
        if c == 1:
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    30
            return t
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    31
        return t + "s"
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    32
    def fmt(t, c):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    33
        return "%d %s" % (c, plural(t, c))
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    34
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    35
    now = time.time()
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    36
    then = date[0]
7682
9c8bbae02e9c templater: fix age filter to state the obvious on future timestamps
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6691
diff changeset
    37
    if then > now:
9c8bbae02e9c templater: fix age filter to state the obvious on future timestamps
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6691
diff changeset
    38
        return 'in the future'
9c8bbae02e9c templater: fix age filter to state the obvious on future timestamps
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6691
diff changeset
    39
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    40
    delta = max(1, int(now - then))
9722
4d9dea174b84 templater: readable dates older than 24 months revert to ISO8601 (issue1006)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9721
diff changeset
    41
    if delta > agescales[0][1] * 2:
4d9dea174b84 templater: readable dates older than 24 months revert to ISO8601 (issue1006)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9721
diff changeset
    42
        return util.shortdate(date)
4d9dea174b84 templater: readable dates older than 24 months revert to ISO8601 (issue1006)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9721
diff changeset
    43
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    44
    for t, s in agescales:
9029
0001e49f1c11 compat: use // for integer division
Alejandro Santos <alejolp@alejolp.com>
parents: 8697
diff changeset
    45
        n = delta // s
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    46
        if n >= 2 or s == 1:
9721
1d75c683ada1 templater: put 'ago' inside the age template filter
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9387
diff changeset
    47
            return '%s ago' % fmt(t, n)
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    48
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    49
para_re = None
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    50
space_re = None
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    51
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    52
def fill(text, width):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    53
    '''fill many paragraphs.'''
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    54
    global para_re, space_re
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    55
    if para_re is None:
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    56
        para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M)
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    57
        space_re = re.compile(r'  +')
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    58
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    59
    def findparas():
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    60
        start = 0
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    61
        while True:
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    62
            m = para_re.search(text, start)
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
            if not m:
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10787
diff changeset
    64
                uctext = unicode(text[start:], encoding.encoding)
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10787
diff changeset
    65
                w = len(uctext)
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10787
diff changeset
    66
                while 0 < w and uctext[w - 1].isspace():
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    67
                    w -= 1
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10787
diff changeset
    68
                yield (uctext[:w].encode(encoding.encoding),
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10787
diff changeset
    69
                       uctext[w:].encode(encoding.encoding))
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    70
                break
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    71
            yield text[start:m.start(0)], m.group(1)
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    72
            start = m.end(1)
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    73
11297
d320e70442a5 replace Python standard textwrap by MBCS sensitive one for i18n text
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 10787
diff changeset
    74
    return "".join([space_re.sub(' ', util.wrap(para, width=width)) + rest
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    75
                    for para, rest in findparas()])
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    76
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    77
def firstline(text):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    78
    '''return the first line of text'''
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    79
    try:
9136
31177742f54a for calls expecting bool args, pass bool instead of int
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9029
diff changeset
    80
        return text.splitlines(True)[0].rstrip('\r\n')
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    81
    except IndexError:
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    82
        return ''
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    83
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    84
def nl2br(text):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    85
    '''replace raw newlines with xhtml line breaks.'''
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    86
    return text.replace('\n', '<br/>\n')
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    87
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    88
def obfuscate(text):
7948
de377b1a9a84 move encoding bits from util to encoding
Matt Mackall <mpm@selenic.com>
parents: 7682
diff changeset
    89
    text = unicode(text, encoding.encoding, 'replace')
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    90
    return ''.join(['&#%d;' % ord(c) for c in text])
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    91
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    92
def domain(author):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    93
    '''get domain of author, or empty string if none.'''
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    94
    f = author.find('@')
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    95
    if f == -1:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    96
        return ''
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    97
    author = author[f + 1:]
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    98
    f = author.find('>')
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    99
    if f >= 0:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   100
        author = author[:f]
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   101
    return author
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   102
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   103
def person(author):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   104
    '''get name of author, or else username.'''
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   105
    if not '@' in author:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   106
        return author
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   107
    f = author.find('<')
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   108
    if f == -1:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   109
        return util.shortuser(author)
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   110
    return author[:f].rstrip()
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   111
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   112
def indent(text, prefix):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   113
    '''indent each non-empty line of text after first with prefix.'''
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   114
    lines = text.splitlines()
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   115
    num_lines = len(lines)
9387
20ed9909dbd9 templatefilters: indent: do not compute text.endswith('\n') in each iteration
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9136
diff changeset
   116
    endswithnewline = text[-1:] == '\n'
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   117
    def indenter():
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   118
        for i in xrange(num_lines):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   119
            l = lines[i]
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   120
            if i and l.strip():
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   121
                yield prefix
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   122
            yield l
9387
20ed9909dbd9 templatefilters: indent: do not compute text.endswith('\n') in each iteration
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9136
diff changeset
   123
            if i < num_lines - 1 or endswithnewline:
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   124
                yield '\n'
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   125
    return "".join(indenter())
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   126
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   127
def permissions(flags):
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   128
    if "l" in flags:
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   129
        return "lrwxrwxrwx"
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   130
    if "x" in flags:
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   131
        return "-rwxr-xr-x"
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   132
    return "-rw-r--r--"
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   133
6174
434139080ed4 Permit XML entities to be escaped in template output.
Jesse Glick <jesse.glick@sun.com>
parents: 6134
diff changeset
   134
def xmlescape(text):
434139080ed4 Permit XML entities to be escaped in template output.
Jesse Glick <jesse.glick@sun.com>
parents: 6134
diff changeset
   135
    text = (text
434139080ed4 Permit XML entities to be escaped in template output.
Jesse Glick <jesse.glick@sun.com>
parents: 6134
diff changeset
   136
            .replace('&', '&amp;')
434139080ed4 Permit XML entities to be escaped in template output.
Jesse Glick <jesse.glick@sun.com>
parents: 6134
diff changeset
   137
            .replace('<', '&lt;')
434139080ed4 Permit XML entities to be escaped in template output.
Jesse Glick <jesse.glick@sun.com>
parents: 6134
diff changeset
   138
            .replace('>', '&gt;')
434139080ed4 Permit XML entities to be escaped in template output.
Jesse Glick <jesse.glick@sun.com>
parents: 6134
diff changeset
   139
            .replace('"', '&quot;')
434139080ed4 Permit XML entities to be escaped in template output.
Jesse Glick <jesse.glick@sun.com>
parents: 6134
diff changeset
   140
            .replace("'", '&#39;')) # &apos; invalid in HTML
434139080ed4 Permit XML entities to be escaped in template output.
Jesse Glick <jesse.glick@sun.com>
parents: 6134
diff changeset
   141
    return re.sub('[\x00-\x08\x0B\x0C\x0E-\x1F]', ' ', text)
434139080ed4 Permit XML entities to be escaped in template output.
Jesse Glick <jesse.glick@sun.com>
parents: 6134
diff changeset
   142
11891
0bedf3a2062a templatefilters: unnest uescape()
Patrick Mezard <pmezard@gmail.com>
parents: 11890
diff changeset
   143
def uescape(c):
0bedf3a2062a templatefilters: unnest uescape()
Patrick Mezard <pmezard@gmail.com>
parents: 11890
diff changeset
   144
    if ord(c) < 0x80:
0bedf3a2062a templatefilters: unnest uescape()
Patrick Mezard <pmezard@gmail.com>
parents: 11890
diff changeset
   145
        return c
0bedf3a2062a templatefilters: unnest uescape()
Patrick Mezard <pmezard@gmail.com>
parents: 11890
diff changeset
   146
    else:
0bedf3a2062a templatefilters: unnest uescape()
Patrick Mezard <pmezard@gmail.com>
parents: 11890
diff changeset
   147
        return '\\u%04x' % ord(c)
0bedf3a2062a templatefilters: unnest uescape()
Patrick Mezard <pmezard@gmail.com>
parents: 11890
diff changeset
   148
6691
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   149
_escapes = [
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   150
    ('\\', '\\\\'), ('"', '\\"'), ('\t', '\\t'), ('\n', '\\n'),
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   151
    ('\r', '\\r'), ('\f', '\\f'), ('\b', '\\b'),
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   152
]
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   153
8014
6a77ba181bc6 templatefilters: split out jsonescape() function
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7948
diff changeset
   154
def jsonescape(s):
6a77ba181bc6 templatefilters: split out jsonescape() function
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7948
diff changeset
   155
    for k, v in _escapes:
6a77ba181bc6 templatefilters: split out jsonescape() function
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7948
diff changeset
   156
        s = s.replace(k, v)
11890
9dac951d0185 templatefilters: use \uxxxx style escape for JSON string
Yuya Nishihara <yuya@tcha.org>
parents: 11765
diff changeset
   157
    return ''.join(uescape(c) for c in s)
8014
6a77ba181bc6 templatefilters: split out jsonescape() function
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7948
diff changeset
   158
6691
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   159
def json(obj):
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   160
    if obj is None or obj is False or obj is True:
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   161
        return {None: 'null', False: 'false', True: 'true'}[obj]
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   162
    elif isinstance(obj, int) or isinstance(obj, float):
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   163
        return str(obj)
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   164
    elif isinstance(obj, str):
11765
aff419e260f9 templatefilters: make json filter handle multibyte characters correctly
Yuya Nishihara <yuya@tcha.org>
parents: 11297
diff changeset
   165
        u = unicode(obj, encoding.encoding, 'replace')
11890
9dac951d0185 templatefilters: use \uxxxx style escape for JSON string
Yuya Nishihara <yuya@tcha.org>
parents: 11765
diff changeset
   166
        return '"%s"' % jsonescape(u)
6691
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   167
    elif isinstance(obj, unicode):
11890
9dac951d0185 templatefilters: use \uxxxx style escape for JSON string
Yuya Nishihara <yuya@tcha.org>
parents: 11765
diff changeset
   168
        return '"%s"' % jsonescape(obj)
6691
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   169
    elif hasattr(obj, 'keys'):
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   170
        out = []
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   171
        for k, v in obj.iteritems():
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   172
            s = '%s: %s' % (json(k), json(v))
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   173
            out.append(s)
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   174
        return '{' + ', '.join(out) + '}'
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   175
    elif hasattr(obj, '__iter__'):
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   176
        out = []
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   177
        for i in obj:
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   178
            out.append(json(i))
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   179
        return '[' + ', '.join(out) + ']'
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   180
    else:
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   181
        raise TypeError('cannot encode type %s' % obj.__class__.__name__)
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   182
8158
1bef3656d9fe templatefilters: add new stripdir filter
Aleix Conchillo Flaque <aleix@member.fsf.org>
parents: 8014
diff changeset
   183
def stripdir(text):
1bef3656d9fe templatefilters: add new stripdir filter
Aleix Conchillo Flaque <aleix@member.fsf.org>
parents: 8014
diff changeset
   184
    '''Treat the text as path and strip a directory level, if possible.'''
1bef3656d9fe templatefilters: add new stripdir filter
Aleix Conchillo Flaque <aleix@member.fsf.org>
parents: 8014
diff changeset
   185
    dir = os.path.dirname(text)
1bef3656d9fe templatefilters: add new stripdir filter
Aleix Conchillo Flaque <aleix@member.fsf.org>
parents: 8014
diff changeset
   186
    if dir == "":
1bef3656d9fe templatefilters: add new stripdir filter
Aleix Conchillo Flaque <aleix@member.fsf.org>
parents: 8014
diff changeset
   187
        return os.path.basename(text)
1bef3656d9fe templatefilters: add new stripdir filter
Aleix Conchillo Flaque <aleix@member.fsf.org>
parents: 8014
diff changeset
   188
    else:
1bef3656d9fe templatefilters: add new stripdir filter
Aleix Conchillo Flaque <aleix@member.fsf.org>
parents: 8014
diff changeset
   189
        return dir
1bef3656d9fe templatefilters: add new stripdir filter
Aleix Conchillo Flaque <aleix@member.fsf.org>
parents: 8014
diff changeset
   190
8234
27dbe534397b templatefilters: add "nonempty" template filter
Rocco Rutte <pdmef@gmx.net>
parents: 8225
diff changeset
   191
def nonempty(str):
8389
4b798b100c32 indentation cleanup
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 8360
diff changeset
   192
    return str or "(none)"
8234
27dbe534397b templatefilters: add "nonempty" template filter
Rocco Rutte <pdmef@gmx.net>
parents: 8225
diff changeset
   193
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   194
filters = {
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   195
    "addbreaks": nl2br,
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   196
    "basename": os.path.basename,
8158
1bef3656d9fe templatefilters: add new stripdir filter
Aleix Conchillo Flaque <aleix@member.fsf.org>
parents: 8014
diff changeset
   197
    "stripdir": stripdir,
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   198
    "age": age,
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   199
    "date": lambda x: util.datestr(x),
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   200
    "domain": domain,
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   201
    "email": util.email,
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   202
    "escape": lambda x: cgi.escape(x, True),
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   203
    "fill68": lambda x: fill(x, width=68),
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   204
    "fill76": lambda x: fill(x, width=76),
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   205
    "firstline": firstline,
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   206
    "tabindent": lambda x: indent(x, '\t'),
6229
c3182eeb70ea dates: improve timezone handling
Matt Mackall <mpm@selenic.com>
parents: 6174
diff changeset
   207
    "hgdate": lambda x: "%d %d" % x,
c3182eeb70ea dates: improve timezone handling
Matt Mackall <mpm@selenic.com>
parents: 6174
diff changeset
   208
    "isodate": lambda x: util.datestr(x, '%Y-%m-%d %H:%M %1%2'),
6319
8999d1249171 Add an {isodatesec} template, to show seconds too.
Giorgos Keramidas <keramida@ceid.upatras.gr>
parents: 6229
diff changeset
   209
    "isodatesec": lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2'),
8014
6a77ba181bc6 templatefilters: split out jsonescape() function
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7948
diff changeset
   210
    "json": json,
6a77ba181bc6 templatefilters: split out jsonescape() function
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7948
diff changeset
   211
    "jsonescape": jsonescape,
8591
08c93b07f5ad templatefilters: add filter to convert date to local date (issue1674)
Henrik Stuart <hg@hstuart.dk>
parents: 8390
diff changeset
   212
    "localdate": lambda x: (x[0], util.makedate()[1]),
8234
27dbe534397b templatefilters: add "nonempty" template filter
Rocco Rutte <pdmef@gmx.net>
parents: 8225
diff changeset
   213
    "nonempty": nonempty,
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   214
    "obfuscate": obfuscate,
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   215
    "permissions": permissions,
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   216
    "person": person,
6229
c3182eeb70ea dates: improve timezone handling
Matt Mackall <mpm@selenic.com>
parents: 6174
diff changeset
   217
    "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S %1%2"),
c3182eeb70ea dates: improve timezone handling
Matt Mackall <mpm@selenic.com>
parents: 6174
diff changeset
   218
    "rfc3339date": lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S%1:%2"),
12371
48a4acd1ccf1 templater: add hex filter.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11891
diff changeset
   219
    "hex": node.hex,
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   220
    "short": lambda x: x[:12],
6134
7b937b26adf7 Make annotae/grep print short dates with -q/--quiet.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 5976
diff changeset
   221
    "shortdate": util.shortdate,
8360
acc202b71619 templater: provide the standard template filters by default
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8234
diff changeset
   222
    "stringify": stringify,
5976
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   223
    "strip": lambda x: x.strip(),
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   224
    "urlescape": lambda x: urllib.quote(x),
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   225
    "user": lambda x: util.shortuser(x),
9f1e6ab76069 templates: move filters to their own module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   226
    "stringescape": lambda x: x.encode('string_escape'),
6174
434139080ed4 Permit XML entities to be escaped in template output.
Jesse Glick <jesse.glick@sun.com>
parents: 6134
diff changeset
   227
    "xmlescape": xmlescape,
6691
0dba955c2636 add graph page to hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6319
diff changeset
   228
}