##// END OF EJS Templates
templates: move filters to their own module...
Matt Mackall -
r5976:9f1e6ab7 default
parent child Browse files
Show More
@@ -0,0 +1,155 b''
1 # template-filters.py - common template expansion filters
2 #
3 # Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 import cgi, re, os, time, urllib, textwrap
9 import util, templater
10
11 agescales = [("second", 1),
12 ("minute", 60),
13 ("hour", 3600),
14 ("day", 3600 * 24),
15 ("week", 3600 * 24 * 7),
16 ("month", 3600 * 24 * 30),
17 ("year", 3600 * 24 * 365)]
18
19 agescales.reverse()
20
21 def age(date):
22 '''turn a (timestamp, tzoff) tuple into an age string.'''
23
24 def plural(t, c):
25 if c == 1:
26 return t
27 return t + "s"
28 def fmt(t, c):
29 return "%d %s" % (c, plural(t, c))
30
31 now = time.time()
32 then = date[0]
33 delta = max(1, int(now - then))
34
35 for t, s in agescales:
36 n = delta / s
37 if n >= 2 or s == 1:
38 return fmt(t, n)
39
40 para_re = None
41 space_re = None
42
43 def fill(text, width):
44 '''fill many paragraphs.'''
45 global para_re, space_re
46 if para_re is None:
47 para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M)
48 space_re = re.compile(r' +')
49
50 def findparas():
51 start = 0
52 while True:
53 m = para_re.search(text, start)
54 if not m:
55 w = len(text)
56 while w > start and text[w-1].isspace(): w -= 1
57 yield text[start:w], text[w:]
58 break
59 yield text[start:m.start(0)], m.group(1)
60 start = m.end(1)
61
62 return "".join([space_re.sub(' ', textwrap.fill(para, width)) + rest
63 for para, rest in findparas()])
64
65 def firstline(text):
66 '''return the first line of text'''
67 try:
68 return text.splitlines(1)[0].rstrip('\r\n')
69 except IndexError:
70 return ''
71
72 def isodate(date):
73 '''turn a (timestamp, tzoff) tuple into an iso 8631 date and time.'''
74 return util.datestr(date, format='%Y-%m-%d %H:%M')
75
76 def hgdate(date):
77 '''turn a (timestamp, tzoff) tuple into an hg cset timestamp.'''
78 return "%d %d" % date
79
80 def nl2br(text):
81 '''replace raw newlines with xhtml line breaks.'''
82 return text.replace('\n', '<br/>\n')
83
84 def obfuscate(text):
85 text = unicode(text, util._encoding, 'replace')
86 return ''.join(['&#%d;' % ord(c) for c in text])
87
88 def domain(author):
89 '''get domain of author, or empty string if none.'''
90 f = author.find('@')
91 if f == -1: return ''
92 author = author[f+1:]
93 f = author.find('>')
94 if f >= 0: author = author[:f]
95 return author
96
97 def person(author):
98 '''get name of author, or else username.'''
99 f = author.find('<')
100 if f == -1: return util.shortuser(author)
101 return author[:f].rstrip()
102
103 def shortdate(date):
104 '''turn (timestamp, tzoff) tuple into iso 8631 date.'''
105 return util.datestr(date, format='%Y-%m-%d', timezone=False)
106
107 def indent(text, prefix):
108 '''indent each non-empty line of text after first with prefix.'''
109 lines = text.splitlines()
110 num_lines = len(lines)
111 def indenter():
112 for i in xrange(num_lines):
113 l = lines[i]
114 if i and l.strip():
115 yield prefix
116 yield l
117 if i < num_lines - 1 or text.endswith('\n'):
118 yield '\n'
119 return "".join(indenter())
120
121 def permissions(flags):
122 if "l" in flags:
123 return "lrwxrwxrwx"
124 if "x" in flags:
125 return "-rwxr-xr-x"
126 return "-rw-r--r--"
127
128 filters = {
129 "addbreaks": nl2br,
130 "basename": os.path.basename,
131 "age": age,
132 "date": lambda x: util.datestr(x),
133 "domain": domain,
134 "email": util.email,
135 "escape": lambda x: cgi.escape(x, True),
136 "fill68": lambda x: fill(x, width=68),
137 "fill76": lambda x: fill(x, width=76),
138 "firstline": firstline,
139 "tabindent": lambda x: indent(x, '\t'),
140 "hgdate": hgdate,
141 "isodate": isodate,
142 "obfuscate": obfuscate,
143 "permissions": permissions,
144 "person": person,
145 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"),
146 "rfc3339date": lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S", True, "%+03d:%02d"),
147 "short": lambda x: x[:12],
148 "shortdate": shortdate,
149 "stringify": templater.stringify,
150 "strip": lambda x: x.strip(),
151 "urlescape": lambda x: urllib.quote(x),
152 "user": lambda x: util.shortuser(x),
153 "stringescape": lambda x: x.encode('string_escape'),
154 }
155
@@ -12,7 +12,7 b''
12 # <alias email> <actual email>
12 # <alias email> <actual email>
13
13
14 from mercurial.i18n import gettext as _
14 from mercurial.i18n import gettext as _
15 from mercurial import hg, mdiff, cmdutil, ui, util, templater, node
15 from mercurial import hg, mdiff, cmdutil, ui, util, templatefilters, node
16 import os, sys
16 import os, sys
17
17
18 def get_tty_width():
18 def get_tty_width():
@@ -27,9 +27,9 b''
27
27
28 import re
28 import re
29 from mercurial.hgweb import hgweb_mod
29 from mercurial.hgweb import hgweb_mod
30 from mercurial import templater
30 from mercurial import templatefilters
31
31
32 orig_escape = templater.common_filters["escape"]
32 orig_escape = templatefilters.filters["escape"]
33
33
34 interhg_table = []
34 interhg_table = []
35
35
@@ -39,7 +39,7 b' def interhg_escape(x):'
39 escstr = regexp.sub(format, escstr)
39 escstr = regexp.sub(format, escstr)
40 return escstr
40 return escstr
41
41
42 templater.common_filters["escape"] = interhg_escape
42 templatefilters.filters["escape"] = interhg_escape
43
43
44 orig_refresh = hgweb_mod.hgweb.refresh
44 orig_refresh = hgweb_mod.hgweb.refresh
45
45
@@ -78,8 +78,8 b" like CVS' $Log$, are not supported. A ke"
78 "Log = {desc}" expands to the first line of the changeset description.
78 "Log = {desc}" expands to the first line of the changeset description.
79 '''
79 '''
80
80
81 from mercurial import commands, cmdutil, context, dispatch, filelog
81 from mercurial import commands, cmdutil, context, dispatch, filelog, revlog
82 from mercurial import patch, localrepo, revlog, templater, util
82 from mercurial import patch, localrepo, templater, templatefilters, util
83 from mercurial.node import *
83 from mercurial.node import *
84 from mercurial.i18n import _
84 from mercurial.i18n import _
85 import re, shutil, sys, tempfile, time
85 import re, shutil, sys, tempfile, time
@@ -130,7 +130,7 b' class kwtemplater(object):'
130 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
130 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
131 self.re_kw = re.compile(kwpat)
131 self.re_kw = re.compile(kwpat)
132
132
133 templater.common_filters['utcdate'] = utcdate
133 templatefilters.filters['utcdate'] = utcdate
134 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
134 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
135 False, '', False)
135 False, '', False)
136
136
@@ -149,7 +149,8 b' class kwtemplater(object):'
149 self.ct.use_template(self.templates[kw])
149 self.ct.use_template(self.templates[kw])
150 self.ui.pushbuffer()
150 self.ui.pushbuffer()
151 self.ct.show(changenode=fnode, root=self.repo.root, file=self.path)
151 self.ct.show(changenode=fnode, root=self.repo.root, file=self.path)
152 return '$%s: %s $' % (kw, templater.firstline(self.ui.popbuffer()))
152 return '$%s: %s $' % (kw, templatefilters.firstline(
153 self.ui.popbuffer()))
153
154
154 return subfunc(kwsub, data)
155 return subfunc(kwsub, data)
155
156
@@ -8,7 +8,7 b''
8 from node import *
8 from node import *
9 from i18n import _
9 from i18n import _
10 import os, sys, bisect, stat
10 import os, sys, bisect, stat
11 import mdiff, bdiff, util, templater, patch, errno
11 import mdiff, bdiff, util, templater, templatefilters, patch, errno
12
12
13 revrangesep = ':'
13 revrangesep = ':'
14
14
@@ -673,7 +673,7 b' class changeset_templater(changeset_prin'
673
673
674 def __init__(self, ui, repo, patch, mapfile, buffered):
674 def __init__(self, ui, repo, patch, mapfile, buffered):
675 changeset_printer.__init__(self, ui, repo, patch, buffered)
675 changeset_printer.__init__(self, ui, repo, patch, buffered)
676 filters = templater.common_filters.copy()
676 filters = templatefilters.filters.copy()
677 filters['formatnode'] = (ui.debugflag and (lambda x: x)
677 filters['formatnode'] = (ui.debugflag and (lambda x: x)
678 or (lambda x: x[:12]))
678 or (lambda x: x[:12]))
679 self.t = templater.templater(mapfile, filters,
679 self.t = templater.templater(mapfile, filters,
@@ -9,7 +9,7 b''
9 import os, mimetypes, re
9 import os, mimetypes, re
10 from mercurial.node import *
10 from mercurial.node import *
11 from mercurial import mdiff, ui, hg, util, archival, patch, hook
11 from mercurial import mdiff, ui, hg, util, archival, patch, hook
12 from mercurial import revlog, templater
12 from mercurial import revlog, templater, templatefilters
13 from common import ErrorResponse, get_mtime, style_map, paritygen, get_contact
13 from common import ErrorResponse, get_mtime, style_map, paritygen, get_contact
14 from request import wsgirequest
14 from request import wsgirequest
15 import webcommands, protocol
15 import webcommands, protocol
@@ -288,7 +288,7 b' class hgweb(object):'
288
288
289 # create the templater
289 # create the templater
290
290
291 tmpl = templater.templater(mapfile, templater.common_filters,
291 tmpl = templater.templater(mapfile, templatefilters.filters,
292 defaults={"url": req.url,
292 defaults={"url": req.url,
293 "staticurl": staticurl,
293 "staticurl": staticurl,
294 "urlbase": urlbase,
294 "urlbase": urlbase,
@@ -8,8 +8,8 b''
8
8
9 import os
9 import os
10 from mercurial.i18n import gettext as _
10 from mercurial.i18n import gettext as _
11 from mercurial import ui, hg, util, templater
11 from mercurial import ui, hg, util, templater, templatefilters
12 from common import ErrorResponse, get_mtime, staticfile, style_map, paritygen, \
12 from common import ErrorResponse, get_mtime, staticfile, style_map, paritygen,\
13 get_contact
13 get_contact
14 from hgweb_mod import hgweb
14 from hgweb_mod import hgweb
15 from request import wsgirequest
15 from request import wsgirequest
@@ -266,7 +266,7 b' class hgwebdir(object):'
266 if self.stripecount is None:
266 if self.stripecount is None:
267 self.stripecount = int(config('web', 'stripes', 1))
267 self.stripecount = int(config('web', 'stripes', 1))
268 mapfile = style_map(templater.templatepath(), style)
268 mapfile = style_map(templater.templatepath(), style)
269 tmpl = templater.templater(mapfile, templater.common_filters,
269 tmpl = templater.templater(mapfile, templatefilters.filters,
270 defaults={"header": header,
270 defaults={"header": header,
271 "footer": footer,
271 "footer": footer,
272 "motd": motd,
272 "motd": motd,
@@ -6,7 +6,7 b''
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import cgi, re, sys, os, time, urllib, util, textwrap
9 import re, sys, os
10
10
11 def parsestring(s, quoted=True):
11 def parsestring(s, quoted=True):
12 '''parse a string using simple c-like syntax.
12 '''parse a string using simple c-like syntax.
@@ -122,157 +122,6 b' class templater(object):'
122 v = self.filters[f](v)
122 v = self.filters[f](v)
123 yield v
123 yield v
124
124
125 agescales = [("second", 1),
126 ("minute", 60),
127 ("hour", 3600),
128 ("day", 3600 * 24),
129 ("week", 3600 * 24 * 7),
130 ("month", 3600 * 24 * 30),
131 ("year", 3600 * 24 * 365)]
132
133 agescales.reverse()
134
135 def age(date):
136 '''turn a (timestamp, tzoff) tuple into an age string.'''
137
138 def plural(t, c):
139 if c == 1:
140 return t
141 return t + "s"
142 def fmt(t, c):
143 return "%d %s" % (c, plural(t, c))
144
145 now = time.time()
146 then = date[0]
147 delta = max(1, int(now - then))
148
149 for t, s in agescales:
150 n = delta / s
151 if n >= 2 or s == 1:
152 return fmt(t, n)
153
154 def stringify(thing):
155 '''turn nested template iterator into string.'''
156 if hasattr(thing, '__iter__'):
157 return "".join([stringify(t) for t in thing if t is not None])
158 return str(thing)
159
160 para_re = None
161 space_re = None
162
163 def fill(text, width):
164 '''fill many paragraphs.'''
165 global para_re, space_re
166 if para_re is None:
167 para_re = re.compile('(\n\n|\n\\s*[-*]\\s*)', re.M)
168 space_re = re.compile(r' +')
169
170 def findparas():
171 start = 0
172 while True:
173 m = para_re.search(text, start)
174 if not m:
175 w = len(text)
176 while w > start and text[w-1].isspace(): w -= 1
177 yield text[start:w], text[w:]
178 break
179 yield text[start:m.start(0)], m.group(1)
180 start = m.end(1)
181
182 return "".join([space_re.sub(' ', textwrap.fill(para, width)) + rest
183 for para, rest in findparas()])
184
185 def firstline(text):
186 '''return the first line of text'''
187 try:
188 return text.splitlines(1)[0].rstrip('\r\n')
189 except IndexError:
190 return ''
191
192 def isodate(date):
193 '''turn a (timestamp, tzoff) tuple into an iso 8631 date and time.'''
194 return util.datestr(date, format='%Y-%m-%d %H:%M')
195
196 def hgdate(date):
197 '''turn a (timestamp, tzoff) tuple into an hg cset timestamp.'''
198 return "%d %d" % date
199
200 def nl2br(text):
201 '''replace raw newlines with xhtml line breaks.'''
202 return text.replace('\n', '<br/>\n')
203
204 def obfuscate(text):
205 text = unicode(text, util._encoding, 'replace')
206 return ''.join(['&#%d;' % ord(c) for c in text])
207
208 def domain(author):
209 '''get domain of author, or empty string if none.'''
210 f = author.find('@')
211 if f == -1: return ''
212 author = author[f+1:]
213 f = author.find('>')
214 if f >= 0: author = author[:f]
215 return author
216
217 def person(author):
218 '''get name of author, or else username.'''
219 f = author.find('<')
220 if f == -1: return util.shortuser(author)
221 return author[:f].rstrip()
222
223 def shortdate(date):
224 '''turn (timestamp, tzoff) tuple into iso 8631 date.'''
225 return util.datestr(date, format='%Y-%m-%d', timezone=False)
226
227 def indent(text, prefix):
228 '''indent each non-empty line of text after first with prefix.'''
229 lines = text.splitlines()
230 num_lines = len(lines)
231 def indenter():
232 for i in xrange(num_lines):
233 l = lines[i]
234 if i and l.strip():
235 yield prefix
236 yield l
237 if i < num_lines - 1 or text.endswith('\n'):
238 yield '\n'
239 return "".join(indenter())
240
241 def permissions(flags):
242 if "l" in flags:
243 return "lrwxrwxrwx"
244 if "x" in flags:
245 return "-rwxr-xr-x"
246 return "-rw-r--r--"
247
248 common_filters = {
249 "addbreaks": nl2br,
250 "basename": os.path.basename,
251 "age": age,
252 "date": lambda x: util.datestr(x),
253 "domain": domain,
254 "email": util.email,
255 "escape": lambda x: cgi.escape(x, True),
256 "fill68": lambda x: fill(x, width=68),
257 "fill76": lambda x: fill(x, width=76),
258 "firstline": firstline,
259 "tabindent": lambda x: indent(x, '\t'),
260 "hgdate": hgdate,
261 "isodate": isodate,
262 "obfuscate": obfuscate,
263 "permissions": permissions,
264 "person": person,
265 "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"),
266 "rfc3339date": lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S", True, "%+03d:%02d"),
267 "short": lambda x: x[:12],
268 "shortdate": shortdate,
269 "stringify": stringify,
270 "strip": lambda x: x.strip(),
271 "urlescape": lambda x: urllib.quote(x),
272 "user": lambda x: util.shortuser(x),
273 "stringescape": lambda x: x.encode('string_escape'),
274 }
275
276 def templatepath(name=None):
125 def templatepath(name=None):
277 '''return location of template file or directory (if no name).
126 '''return location of template file or directory (if no name).
278 returns None if not found.'''
127 returns None if not found.'''
@@ -289,3 +138,9 b' def templatepath(name=None):'
289 if (name and os.path.exists(p)) or os.path.isdir(p):
138 if (name and os.path.exists(p)) or os.path.isdir(p):
290 return os.path.normpath(p)
139 return os.path.normpath(p)
291
140
141 def stringify(thing):
142 '''turn nested template iterator into string.'''
143 if hasattr(thing, '__iter__'):
144 return "".join([stringify(t) for t in thing if t is not None])
145 return str(thing)
146
General Comments 0
You need to be logged in to leave comments. Login now