##// END OF EJS Templates
hgweb: display blamed revision once per block in annotate view...
Denis Laxalde -
r29388:f694e201 default
parent child Browse files
Show More
@@ -1,1298 +1,1303 b''
1 #
1 #
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import cgi
10 import cgi
11 import copy
11 import copy
12 import mimetypes
12 import mimetypes
13 import os
13 import os
14 import re
14 import re
15
15
16 from ..i18n import _
16 from ..i18n import _
17 from ..node import hex, short
17 from ..node import hex, short
18
18
19 from .common import (
19 from .common import (
20 ErrorResponse,
20 ErrorResponse,
21 HTTP_FORBIDDEN,
21 HTTP_FORBIDDEN,
22 HTTP_NOT_FOUND,
22 HTTP_NOT_FOUND,
23 HTTP_OK,
23 HTTP_OK,
24 get_contact,
24 get_contact,
25 paritygen,
25 paritygen,
26 staticfile,
26 staticfile,
27 )
27 )
28
28
29 from .. import (
29 from .. import (
30 archival,
30 archival,
31 encoding,
31 encoding,
32 error,
32 error,
33 graphmod,
33 graphmod,
34 patch,
34 patch,
35 revset,
35 revset,
36 scmutil,
36 scmutil,
37 templatefilters,
37 templatefilters,
38 templater,
38 templater,
39 util,
39 util,
40 )
40 )
41
41
42 from . import (
42 from . import (
43 webutil,
43 webutil,
44 )
44 )
45
45
46 __all__ = []
46 __all__ = []
47 commands = {}
47 commands = {}
48
48
49 class webcommand(object):
49 class webcommand(object):
50 """Decorator used to register a web command handler.
50 """Decorator used to register a web command handler.
51
51
52 The decorator takes as its positional arguments the name/path the
52 The decorator takes as its positional arguments the name/path the
53 command should be accessible under.
53 command should be accessible under.
54
54
55 Usage:
55 Usage:
56
56
57 @webcommand('mycommand')
57 @webcommand('mycommand')
58 def mycommand(web, req, tmpl):
58 def mycommand(web, req, tmpl):
59 pass
59 pass
60 """
60 """
61
61
62 def __init__(self, name):
62 def __init__(self, name):
63 self.name = name
63 self.name = name
64
64
65 def __call__(self, func):
65 def __call__(self, func):
66 __all__.append(self.name)
66 __all__.append(self.name)
67 commands[self.name] = func
67 commands[self.name] = func
68 return func
68 return func
69
69
70 @webcommand('log')
70 @webcommand('log')
71 def log(web, req, tmpl):
71 def log(web, req, tmpl):
72 """
72 """
73 /log[/{revision}[/{path}]]
73 /log[/{revision}[/{path}]]
74 --------------------------
74 --------------------------
75
75
76 Show repository or file history.
76 Show repository or file history.
77
77
78 For URLs of the form ``/log/{revision}``, a list of changesets starting at
78 For URLs of the form ``/log/{revision}``, a list of changesets starting at
79 the specified changeset identifier is shown. If ``{revision}`` is not
79 the specified changeset identifier is shown. If ``{revision}`` is not
80 defined, the default is ``tip``. This form is equivalent to the
80 defined, the default is ``tip``. This form is equivalent to the
81 ``changelog`` handler.
81 ``changelog`` handler.
82
82
83 For URLs of the form ``/log/{revision}/{file}``, the history for a specific
83 For URLs of the form ``/log/{revision}/{file}``, the history for a specific
84 file will be shown. This form is equivalent to the ``filelog`` handler.
84 file will be shown. This form is equivalent to the ``filelog`` handler.
85 """
85 """
86
86
87 if 'file' in req.form and req.form['file'][0]:
87 if 'file' in req.form and req.form['file'][0]:
88 return filelog(web, req, tmpl)
88 return filelog(web, req, tmpl)
89 else:
89 else:
90 return changelog(web, req, tmpl)
90 return changelog(web, req, tmpl)
91
91
92 @webcommand('rawfile')
92 @webcommand('rawfile')
93 def rawfile(web, req, tmpl):
93 def rawfile(web, req, tmpl):
94 guessmime = web.configbool('web', 'guessmime', False)
94 guessmime = web.configbool('web', 'guessmime', False)
95
95
96 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
96 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
97 if not path:
97 if not path:
98 content = manifest(web, req, tmpl)
98 content = manifest(web, req, tmpl)
99 req.respond(HTTP_OK, web.ctype)
99 req.respond(HTTP_OK, web.ctype)
100 return content
100 return content
101
101
102 try:
102 try:
103 fctx = webutil.filectx(web.repo, req)
103 fctx = webutil.filectx(web.repo, req)
104 except error.LookupError as inst:
104 except error.LookupError as inst:
105 try:
105 try:
106 content = manifest(web, req, tmpl)
106 content = manifest(web, req, tmpl)
107 req.respond(HTTP_OK, web.ctype)
107 req.respond(HTTP_OK, web.ctype)
108 return content
108 return content
109 except ErrorResponse:
109 except ErrorResponse:
110 raise inst
110 raise inst
111
111
112 path = fctx.path()
112 path = fctx.path()
113 text = fctx.data()
113 text = fctx.data()
114 mt = 'application/binary'
114 mt = 'application/binary'
115 if guessmime:
115 if guessmime:
116 mt = mimetypes.guess_type(path)[0]
116 mt = mimetypes.guess_type(path)[0]
117 if mt is None:
117 if mt is None:
118 if util.binary(text):
118 if util.binary(text):
119 mt = 'application/binary'
119 mt = 'application/binary'
120 else:
120 else:
121 mt = 'text/plain'
121 mt = 'text/plain'
122 if mt.startswith('text/'):
122 if mt.startswith('text/'):
123 mt += '; charset="%s"' % encoding.encoding
123 mt += '; charset="%s"' % encoding.encoding
124
124
125 req.respond(HTTP_OK, mt, path, body=text)
125 req.respond(HTTP_OK, mt, path, body=text)
126 return []
126 return []
127
127
128 def _filerevision(web, req, tmpl, fctx):
128 def _filerevision(web, req, tmpl, fctx):
129 f = fctx.path()
129 f = fctx.path()
130 text = fctx.data()
130 text = fctx.data()
131 parity = paritygen(web.stripecount)
131 parity = paritygen(web.stripecount)
132
132
133 if util.binary(text):
133 if util.binary(text):
134 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
134 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
135 text = '(binary:%s)' % mt
135 text = '(binary:%s)' % mt
136
136
137 def lines():
137 def lines():
138 for lineno, t in enumerate(text.splitlines(True)):
138 for lineno, t in enumerate(text.splitlines(True)):
139 yield {"line": t,
139 yield {"line": t,
140 "lineid": "l%d" % (lineno + 1),
140 "lineid": "l%d" % (lineno + 1),
141 "linenumber": "% 6d" % (lineno + 1),
141 "linenumber": "% 6d" % (lineno + 1),
142 "parity": next(parity)}
142 "parity": next(parity)}
143
143
144 return tmpl("filerevision",
144 return tmpl("filerevision",
145 file=f,
145 file=f,
146 path=webutil.up(f),
146 path=webutil.up(f),
147 text=lines(),
147 text=lines(),
148 symrev=webutil.symrevorshortnode(req, fctx),
148 symrev=webutil.symrevorshortnode(req, fctx),
149 rename=webutil.renamelink(fctx),
149 rename=webutil.renamelink(fctx),
150 permissions=fctx.manifest().flags(f),
150 permissions=fctx.manifest().flags(f),
151 **webutil.commonentry(web.repo, fctx))
151 **webutil.commonentry(web.repo, fctx))
152
152
153 @webcommand('file')
153 @webcommand('file')
154 def file(web, req, tmpl):
154 def file(web, req, tmpl):
155 """
155 """
156 /file/{revision}[/{path}]
156 /file/{revision}[/{path}]
157 -------------------------
157 -------------------------
158
158
159 Show information about a directory or file in the repository.
159 Show information about a directory or file in the repository.
160
160
161 Info about the ``path`` given as a URL parameter will be rendered.
161 Info about the ``path`` given as a URL parameter will be rendered.
162
162
163 If ``path`` is a directory, information about the entries in that
163 If ``path`` is a directory, information about the entries in that
164 directory will be rendered. This form is equivalent to the ``manifest``
164 directory will be rendered. This form is equivalent to the ``manifest``
165 handler.
165 handler.
166
166
167 If ``path`` is a file, information about that file will be shown via
167 If ``path`` is a file, information about that file will be shown via
168 the ``filerevision`` template.
168 the ``filerevision`` template.
169
169
170 If ``path`` is not defined, information about the root directory will
170 If ``path`` is not defined, information about the root directory will
171 be rendered.
171 be rendered.
172 """
172 """
173 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
173 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
174 if not path:
174 if not path:
175 return manifest(web, req, tmpl)
175 return manifest(web, req, tmpl)
176 try:
176 try:
177 return _filerevision(web, req, tmpl, webutil.filectx(web.repo, req))
177 return _filerevision(web, req, tmpl, webutil.filectx(web.repo, req))
178 except error.LookupError as inst:
178 except error.LookupError as inst:
179 try:
179 try:
180 return manifest(web, req, tmpl)
180 return manifest(web, req, tmpl)
181 except ErrorResponse:
181 except ErrorResponse:
182 raise inst
182 raise inst
183
183
184 def _search(web, req, tmpl):
184 def _search(web, req, tmpl):
185 MODE_REVISION = 'rev'
185 MODE_REVISION = 'rev'
186 MODE_KEYWORD = 'keyword'
186 MODE_KEYWORD = 'keyword'
187 MODE_REVSET = 'revset'
187 MODE_REVSET = 'revset'
188
188
189 def revsearch(ctx):
189 def revsearch(ctx):
190 yield ctx
190 yield ctx
191
191
192 def keywordsearch(query):
192 def keywordsearch(query):
193 lower = encoding.lower
193 lower = encoding.lower
194 qw = lower(query).split()
194 qw = lower(query).split()
195
195
196 def revgen():
196 def revgen():
197 cl = web.repo.changelog
197 cl = web.repo.changelog
198 for i in xrange(len(web.repo) - 1, 0, -100):
198 for i in xrange(len(web.repo) - 1, 0, -100):
199 l = []
199 l = []
200 for j in cl.revs(max(0, i - 99), i):
200 for j in cl.revs(max(0, i - 99), i):
201 ctx = web.repo[j]
201 ctx = web.repo[j]
202 l.append(ctx)
202 l.append(ctx)
203 l.reverse()
203 l.reverse()
204 for e in l:
204 for e in l:
205 yield e
205 yield e
206
206
207 for ctx in revgen():
207 for ctx in revgen():
208 miss = 0
208 miss = 0
209 for q in qw:
209 for q in qw:
210 if not (q in lower(ctx.user()) or
210 if not (q in lower(ctx.user()) or
211 q in lower(ctx.description()) or
211 q in lower(ctx.description()) or
212 q in lower(" ".join(ctx.files()))):
212 q in lower(" ".join(ctx.files()))):
213 miss = 1
213 miss = 1
214 break
214 break
215 if miss:
215 if miss:
216 continue
216 continue
217
217
218 yield ctx
218 yield ctx
219
219
220 def revsetsearch(revs):
220 def revsetsearch(revs):
221 for r in revs:
221 for r in revs:
222 yield web.repo[r]
222 yield web.repo[r]
223
223
224 searchfuncs = {
224 searchfuncs = {
225 MODE_REVISION: (revsearch, 'exact revision search'),
225 MODE_REVISION: (revsearch, 'exact revision search'),
226 MODE_KEYWORD: (keywordsearch, 'literal keyword search'),
226 MODE_KEYWORD: (keywordsearch, 'literal keyword search'),
227 MODE_REVSET: (revsetsearch, 'revset expression search'),
227 MODE_REVSET: (revsetsearch, 'revset expression search'),
228 }
228 }
229
229
230 def getsearchmode(query):
230 def getsearchmode(query):
231 try:
231 try:
232 ctx = web.repo[query]
232 ctx = web.repo[query]
233 except (error.RepoError, error.LookupError):
233 except (error.RepoError, error.LookupError):
234 # query is not an exact revision pointer, need to
234 # query is not an exact revision pointer, need to
235 # decide if it's a revset expression or keywords
235 # decide if it's a revset expression or keywords
236 pass
236 pass
237 else:
237 else:
238 return MODE_REVISION, ctx
238 return MODE_REVISION, ctx
239
239
240 revdef = 'reverse(%s)' % query
240 revdef = 'reverse(%s)' % query
241 try:
241 try:
242 tree = revset.parse(revdef)
242 tree = revset.parse(revdef)
243 except error.ParseError:
243 except error.ParseError:
244 # can't parse to a revset tree
244 # can't parse to a revset tree
245 return MODE_KEYWORD, query
245 return MODE_KEYWORD, query
246
246
247 if revset.depth(tree) <= 2:
247 if revset.depth(tree) <= 2:
248 # no revset syntax used
248 # no revset syntax used
249 return MODE_KEYWORD, query
249 return MODE_KEYWORD, query
250
250
251 if any((token, (value or '')[:3]) == ('string', 're:')
251 if any((token, (value or '')[:3]) == ('string', 're:')
252 for token, value, pos in revset.tokenize(revdef)):
252 for token, value, pos in revset.tokenize(revdef)):
253 return MODE_KEYWORD, query
253 return MODE_KEYWORD, query
254
254
255 funcsused = revset.funcsused(tree)
255 funcsused = revset.funcsused(tree)
256 if not funcsused.issubset(revset.safesymbols):
256 if not funcsused.issubset(revset.safesymbols):
257 return MODE_KEYWORD, query
257 return MODE_KEYWORD, query
258
258
259 mfunc = revset.match(web.repo.ui, revdef)
259 mfunc = revset.match(web.repo.ui, revdef)
260 try:
260 try:
261 revs = mfunc(web.repo)
261 revs = mfunc(web.repo)
262 return MODE_REVSET, revs
262 return MODE_REVSET, revs
263 # ParseError: wrongly placed tokens, wrongs arguments, etc
263 # ParseError: wrongly placed tokens, wrongs arguments, etc
264 # RepoLookupError: no such revision, e.g. in 'revision:'
264 # RepoLookupError: no such revision, e.g. in 'revision:'
265 # Abort: bookmark/tag not exists
265 # Abort: bookmark/tag not exists
266 # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
266 # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
267 except (error.ParseError, error.RepoLookupError, error.Abort,
267 except (error.ParseError, error.RepoLookupError, error.Abort,
268 LookupError):
268 LookupError):
269 return MODE_KEYWORD, query
269 return MODE_KEYWORD, query
270
270
271 def changelist(**map):
271 def changelist(**map):
272 count = 0
272 count = 0
273
273
274 for ctx in searchfunc[0](funcarg):
274 for ctx in searchfunc[0](funcarg):
275 count += 1
275 count += 1
276 n = ctx.node()
276 n = ctx.node()
277 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
277 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
278 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
278 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
279
279
280 yield tmpl('searchentry',
280 yield tmpl('searchentry',
281 parity=next(parity),
281 parity=next(parity),
282 changelogtag=showtags,
282 changelogtag=showtags,
283 files=files,
283 files=files,
284 **webutil.commonentry(web.repo, ctx))
284 **webutil.commonentry(web.repo, ctx))
285
285
286 if count >= revcount:
286 if count >= revcount:
287 break
287 break
288
288
289 query = req.form['rev'][0]
289 query = req.form['rev'][0]
290 revcount = web.maxchanges
290 revcount = web.maxchanges
291 if 'revcount' in req.form:
291 if 'revcount' in req.form:
292 try:
292 try:
293 revcount = int(req.form.get('revcount', [revcount])[0])
293 revcount = int(req.form.get('revcount', [revcount])[0])
294 revcount = max(revcount, 1)
294 revcount = max(revcount, 1)
295 tmpl.defaults['sessionvars']['revcount'] = revcount
295 tmpl.defaults['sessionvars']['revcount'] = revcount
296 except ValueError:
296 except ValueError:
297 pass
297 pass
298
298
299 lessvars = copy.copy(tmpl.defaults['sessionvars'])
299 lessvars = copy.copy(tmpl.defaults['sessionvars'])
300 lessvars['revcount'] = max(revcount / 2, 1)
300 lessvars['revcount'] = max(revcount / 2, 1)
301 lessvars['rev'] = query
301 lessvars['rev'] = query
302 morevars = copy.copy(tmpl.defaults['sessionvars'])
302 morevars = copy.copy(tmpl.defaults['sessionvars'])
303 morevars['revcount'] = revcount * 2
303 morevars['revcount'] = revcount * 2
304 morevars['rev'] = query
304 morevars['rev'] = query
305
305
306 mode, funcarg = getsearchmode(query)
306 mode, funcarg = getsearchmode(query)
307
307
308 if 'forcekw' in req.form:
308 if 'forcekw' in req.form:
309 showforcekw = ''
309 showforcekw = ''
310 showunforcekw = searchfuncs[mode][1]
310 showunforcekw = searchfuncs[mode][1]
311 mode = MODE_KEYWORD
311 mode = MODE_KEYWORD
312 funcarg = query
312 funcarg = query
313 else:
313 else:
314 if mode != MODE_KEYWORD:
314 if mode != MODE_KEYWORD:
315 showforcekw = searchfuncs[MODE_KEYWORD][1]
315 showforcekw = searchfuncs[MODE_KEYWORD][1]
316 else:
316 else:
317 showforcekw = ''
317 showforcekw = ''
318 showunforcekw = ''
318 showunforcekw = ''
319
319
320 searchfunc = searchfuncs[mode]
320 searchfunc = searchfuncs[mode]
321
321
322 tip = web.repo['tip']
322 tip = web.repo['tip']
323 parity = paritygen(web.stripecount)
323 parity = paritygen(web.stripecount)
324
324
325 return tmpl('search', query=query, node=tip.hex(), symrev='tip',
325 return tmpl('search', query=query, node=tip.hex(), symrev='tip',
326 entries=changelist, archives=web.archivelist("tip"),
326 entries=changelist, archives=web.archivelist("tip"),
327 morevars=morevars, lessvars=lessvars,
327 morevars=morevars, lessvars=lessvars,
328 modedesc=searchfunc[1],
328 modedesc=searchfunc[1],
329 showforcekw=showforcekw, showunforcekw=showunforcekw)
329 showforcekw=showforcekw, showunforcekw=showunforcekw)
330
330
331 @webcommand('changelog')
331 @webcommand('changelog')
332 def changelog(web, req, tmpl, shortlog=False):
332 def changelog(web, req, tmpl, shortlog=False):
333 """
333 """
334 /changelog[/{revision}]
334 /changelog[/{revision}]
335 -----------------------
335 -----------------------
336
336
337 Show information about multiple changesets.
337 Show information about multiple changesets.
338
338
339 If the optional ``revision`` URL argument is absent, information about
339 If the optional ``revision`` URL argument is absent, information about
340 all changesets starting at ``tip`` will be rendered. If the ``revision``
340 all changesets starting at ``tip`` will be rendered. If the ``revision``
341 argument is present, changesets will be shown starting from the specified
341 argument is present, changesets will be shown starting from the specified
342 revision.
342 revision.
343
343
344 If ``revision`` is absent, the ``rev`` query string argument may be
344 If ``revision`` is absent, the ``rev`` query string argument may be
345 defined. This will perform a search for changesets.
345 defined. This will perform a search for changesets.
346
346
347 The argument for ``rev`` can be a single revision, a revision set,
347 The argument for ``rev`` can be a single revision, a revision set,
348 or a literal keyword to search for in changeset data (equivalent to
348 or a literal keyword to search for in changeset data (equivalent to
349 :hg:`log -k`).
349 :hg:`log -k`).
350
350
351 The ``revcount`` query string argument defines the maximum numbers of
351 The ``revcount`` query string argument defines the maximum numbers of
352 changesets to render.
352 changesets to render.
353
353
354 For non-searches, the ``changelog`` template will be rendered.
354 For non-searches, the ``changelog`` template will be rendered.
355 """
355 """
356
356
357 query = ''
357 query = ''
358 if 'node' in req.form:
358 if 'node' in req.form:
359 ctx = webutil.changectx(web.repo, req)
359 ctx = webutil.changectx(web.repo, req)
360 symrev = webutil.symrevorshortnode(req, ctx)
360 symrev = webutil.symrevorshortnode(req, ctx)
361 elif 'rev' in req.form:
361 elif 'rev' in req.form:
362 return _search(web, req, tmpl)
362 return _search(web, req, tmpl)
363 else:
363 else:
364 ctx = web.repo['tip']
364 ctx = web.repo['tip']
365 symrev = 'tip'
365 symrev = 'tip'
366
366
367 def changelist():
367 def changelist():
368 revs = []
368 revs = []
369 if pos != -1:
369 if pos != -1:
370 revs = web.repo.changelog.revs(pos, 0)
370 revs = web.repo.changelog.revs(pos, 0)
371 curcount = 0
371 curcount = 0
372 for rev in revs:
372 for rev in revs:
373 curcount += 1
373 curcount += 1
374 if curcount > revcount + 1:
374 if curcount > revcount + 1:
375 break
375 break
376
376
377 entry = webutil.changelistentry(web, web.repo[rev], tmpl)
377 entry = webutil.changelistentry(web, web.repo[rev], tmpl)
378 entry['parity'] = next(parity)
378 entry['parity'] = next(parity)
379 yield entry
379 yield entry
380
380
381 if shortlog:
381 if shortlog:
382 revcount = web.maxshortchanges
382 revcount = web.maxshortchanges
383 else:
383 else:
384 revcount = web.maxchanges
384 revcount = web.maxchanges
385
385
386 if 'revcount' in req.form:
386 if 'revcount' in req.form:
387 try:
387 try:
388 revcount = int(req.form.get('revcount', [revcount])[0])
388 revcount = int(req.form.get('revcount', [revcount])[0])
389 revcount = max(revcount, 1)
389 revcount = max(revcount, 1)
390 tmpl.defaults['sessionvars']['revcount'] = revcount
390 tmpl.defaults['sessionvars']['revcount'] = revcount
391 except ValueError:
391 except ValueError:
392 pass
392 pass
393
393
394 lessvars = copy.copy(tmpl.defaults['sessionvars'])
394 lessvars = copy.copy(tmpl.defaults['sessionvars'])
395 lessvars['revcount'] = max(revcount / 2, 1)
395 lessvars['revcount'] = max(revcount / 2, 1)
396 morevars = copy.copy(tmpl.defaults['sessionvars'])
396 morevars = copy.copy(tmpl.defaults['sessionvars'])
397 morevars['revcount'] = revcount * 2
397 morevars['revcount'] = revcount * 2
398
398
399 count = len(web.repo)
399 count = len(web.repo)
400 pos = ctx.rev()
400 pos = ctx.rev()
401 parity = paritygen(web.stripecount)
401 parity = paritygen(web.stripecount)
402
402
403 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
403 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
404
404
405 entries = list(changelist())
405 entries = list(changelist())
406 latestentry = entries[:1]
406 latestentry = entries[:1]
407 if len(entries) > revcount:
407 if len(entries) > revcount:
408 nextentry = entries[-1:]
408 nextentry = entries[-1:]
409 entries = entries[:-1]
409 entries = entries[:-1]
410 else:
410 else:
411 nextentry = []
411 nextentry = []
412
412
413 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
413 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
414 node=ctx.hex(), rev=pos, symrev=symrev, changesets=count,
414 node=ctx.hex(), rev=pos, symrev=symrev, changesets=count,
415 entries=entries,
415 entries=entries,
416 latestentry=latestentry, nextentry=nextentry,
416 latestentry=latestentry, nextentry=nextentry,
417 archives=web.archivelist("tip"), revcount=revcount,
417 archives=web.archivelist("tip"), revcount=revcount,
418 morevars=morevars, lessvars=lessvars, query=query)
418 morevars=morevars, lessvars=lessvars, query=query)
419
419
420 @webcommand('shortlog')
420 @webcommand('shortlog')
421 def shortlog(web, req, tmpl):
421 def shortlog(web, req, tmpl):
422 """
422 """
423 /shortlog
423 /shortlog
424 ---------
424 ---------
425
425
426 Show basic information about a set of changesets.
426 Show basic information about a set of changesets.
427
427
428 This accepts the same parameters as the ``changelog`` handler. The only
428 This accepts the same parameters as the ``changelog`` handler. The only
429 difference is the ``shortlog`` template will be rendered instead of the
429 difference is the ``shortlog`` template will be rendered instead of the
430 ``changelog`` template.
430 ``changelog`` template.
431 """
431 """
432 return changelog(web, req, tmpl, shortlog=True)
432 return changelog(web, req, tmpl, shortlog=True)
433
433
434 @webcommand('changeset')
434 @webcommand('changeset')
435 def changeset(web, req, tmpl):
435 def changeset(web, req, tmpl):
436 """
436 """
437 /changeset[/{revision}]
437 /changeset[/{revision}]
438 -----------------------
438 -----------------------
439
439
440 Show information about a single changeset.
440 Show information about a single changeset.
441
441
442 A URL path argument is the changeset identifier to show. See ``hg help
442 A URL path argument is the changeset identifier to show. See ``hg help
443 revisions`` for possible values. If not defined, the ``tip`` changeset
443 revisions`` for possible values. If not defined, the ``tip`` changeset
444 will be shown.
444 will be shown.
445
445
446 The ``changeset`` template is rendered. Contents of the ``changesettag``,
446 The ``changeset`` template is rendered. Contents of the ``changesettag``,
447 ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many
447 ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many
448 templates related to diffs may all be used to produce the output.
448 templates related to diffs may all be used to produce the output.
449 """
449 """
450 ctx = webutil.changectx(web.repo, req)
450 ctx = webutil.changectx(web.repo, req)
451
451
452 return tmpl('changeset', **webutil.changesetentry(web, req, tmpl, ctx))
452 return tmpl('changeset', **webutil.changesetentry(web, req, tmpl, ctx))
453
453
454 rev = webcommand('rev')(changeset)
454 rev = webcommand('rev')(changeset)
455
455
456 def decodepath(path):
456 def decodepath(path):
457 """Hook for mapping a path in the repository to a path in the
457 """Hook for mapping a path in the repository to a path in the
458 working copy.
458 working copy.
459
459
460 Extensions (e.g., largefiles) can override this to remap files in
460 Extensions (e.g., largefiles) can override this to remap files in
461 the virtual file system presented by the manifest command below."""
461 the virtual file system presented by the manifest command below."""
462 return path
462 return path
463
463
464 @webcommand('manifest')
464 @webcommand('manifest')
465 def manifest(web, req, tmpl):
465 def manifest(web, req, tmpl):
466 """
466 """
467 /manifest[/{revision}[/{path}]]
467 /manifest[/{revision}[/{path}]]
468 -------------------------------
468 -------------------------------
469
469
470 Show information about a directory.
470 Show information about a directory.
471
471
472 If the URL path arguments are omitted, information about the root
472 If the URL path arguments are omitted, information about the root
473 directory for the ``tip`` changeset will be shown.
473 directory for the ``tip`` changeset will be shown.
474
474
475 Because this handler can only show information for directories, it
475 Because this handler can only show information for directories, it
476 is recommended to use the ``file`` handler instead, as it can handle both
476 is recommended to use the ``file`` handler instead, as it can handle both
477 directories and files.
477 directories and files.
478
478
479 The ``manifest`` template will be rendered for this handler.
479 The ``manifest`` template will be rendered for this handler.
480 """
480 """
481 if 'node' in req.form:
481 if 'node' in req.form:
482 ctx = webutil.changectx(web.repo, req)
482 ctx = webutil.changectx(web.repo, req)
483 symrev = webutil.symrevorshortnode(req, ctx)
483 symrev = webutil.symrevorshortnode(req, ctx)
484 else:
484 else:
485 ctx = web.repo['tip']
485 ctx = web.repo['tip']
486 symrev = 'tip'
486 symrev = 'tip'
487 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
487 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
488 mf = ctx.manifest()
488 mf = ctx.manifest()
489 node = ctx.node()
489 node = ctx.node()
490
490
491 files = {}
491 files = {}
492 dirs = {}
492 dirs = {}
493 parity = paritygen(web.stripecount)
493 parity = paritygen(web.stripecount)
494
494
495 if path and path[-1] != "/":
495 if path and path[-1] != "/":
496 path += "/"
496 path += "/"
497 l = len(path)
497 l = len(path)
498 abspath = "/" + path
498 abspath = "/" + path
499
499
500 for full, n in mf.iteritems():
500 for full, n in mf.iteritems():
501 # the virtual path (working copy path) used for the full
501 # the virtual path (working copy path) used for the full
502 # (repository) path
502 # (repository) path
503 f = decodepath(full)
503 f = decodepath(full)
504
504
505 if f[:l] != path:
505 if f[:l] != path:
506 continue
506 continue
507 remain = f[l:]
507 remain = f[l:]
508 elements = remain.split('/')
508 elements = remain.split('/')
509 if len(elements) == 1:
509 if len(elements) == 1:
510 files[remain] = full
510 files[remain] = full
511 else:
511 else:
512 h = dirs # need to retain ref to dirs (root)
512 h = dirs # need to retain ref to dirs (root)
513 for elem in elements[0:-1]:
513 for elem in elements[0:-1]:
514 if elem not in h:
514 if elem not in h:
515 h[elem] = {}
515 h[elem] = {}
516 h = h[elem]
516 h = h[elem]
517 if len(h) > 1:
517 if len(h) > 1:
518 break
518 break
519 h[None] = None # denotes files present
519 h[None] = None # denotes files present
520
520
521 if mf and not files and not dirs:
521 if mf and not files and not dirs:
522 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
522 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
523
523
524 def filelist(**map):
524 def filelist(**map):
525 for f in sorted(files):
525 for f in sorted(files):
526 full = files[f]
526 full = files[f]
527
527
528 fctx = ctx.filectx(full)
528 fctx = ctx.filectx(full)
529 yield {"file": full,
529 yield {"file": full,
530 "parity": next(parity),
530 "parity": next(parity),
531 "basename": f,
531 "basename": f,
532 "date": fctx.date(),
532 "date": fctx.date(),
533 "size": fctx.size(),
533 "size": fctx.size(),
534 "permissions": mf.flags(full)}
534 "permissions": mf.flags(full)}
535
535
536 def dirlist(**map):
536 def dirlist(**map):
537 for d in sorted(dirs):
537 for d in sorted(dirs):
538
538
539 emptydirs = []
539 emptydirs = []
540 h = dirs[d]
540 h = dirs[d]
541 while isinstance(h, dict) and len(h) == 1:
541 while isinstance(h, dict) and len(h) == 1:
542 k, v = h.items()[0]
542 k, v = h.items()[0]
543 if v:
543 if v:
544 emptydirs.append(k)
544 emptydirs.append(k)
545 h = v
545 h = v
546
546
547 path = "%s%s" % (abspath, d)
547 path = "%s%s" % (abspath, d)
548 yield {"parity": next(parity),
548 yield {"parity": next(parity),
549 "path": path,
549 "path": path,
550 "emptydirs": "/".join(emptydirs),
550 "emptydirs": "/".join(emptydirs),
551 "basename": d}
551 "basename": d}
552
552
553 return tmpl("manifest",
553 return tmpl("manifest",
554 symrev=symrev,
554 symrev=symrev,
555 path=abspath,
555 path=abspath,
556 up=webutil.up(abspath),
556 up=webutil.up(abspath),
557 upparity=next(parity),
557 upparity=next(parity),
558 fentries=filelist,
558 fentries=filelist,
559 dentries=dirlist,
559 dentries=dirlist,
560 archives=web.archivelist(hex(node)),
560 archives=web.archivelist(hex(node)),
561 **webutil.commonentry(web.repo, ctx))
561 **webutil.commonentry(web.repo, ctx))
562
562
563 @webcommand('tags')
563 @webcommand('tags')
564 def tags(web, req, tmpl):
564 def tags(web, req, tmpl):
565 """
565 """
566 /tags
566 /tags
567 -----
567 -----
568
568
569 Show information about tags.
569 Show information about tags.
570
570
571 No arguments are accepted.
571 No arguments are accepted.
572
572
573 The ``tags`` template is rendered.
573 The ``tags`` template is rendered.
574 """
574 """
575 i = list(reversed(web.repo.tagslist()))
575 i = list(reversed(web.repo.tagslist()))
576 parity = paritygen(web.stripecount)
576 parity = paritygen(web.stripecount)
577
577
578 def entries(notip, latestonly, **map):
578 def entries(notip, latestonly, **map):
579 t = i
579 t = i
580 if notip:
580 if notip:
581 t = [(k, n) for k, n in i if k != "tip"]
581 t = [(k, n) for k, n in i if k != "tip"]
582 if latestonly:
582 if latestonly:
583 t = t[:1]
583 t = t[:1]
584 for k, n in t:
584 for k, n in t:
585 yield {"parity": next(parity),
585 yield {"parity": next(parity),
586 "tag": k,
586 "tag": k,
587 "date": web.repo[n].date(),
587 "date": web.repo[n].date(),
588 "node": hex(n)}
588 "node": hex(n)}
589
589
590 return tmpl("tags",
590 return tmpl("tags",
591 node=hex(web.repo.changelog.tip()),
591 node=hex(web.repo.changelog.tip()),
592 entries=lambda **x: entries(False, False, **x),
592 entries=lambda **x: entries(False, False, **x),
593 entriesnotip=lambda **x: entries(True, False, **x),
593 entriesnotip=lambda **x: entries(True, False, **x),
594 latestentry=lambda **x: entries(True, True, **x))
594 latestentry=lambda **x: entries(True, True, **x))
595
595
596 @webcommand('bookmarks')
596 @webcommand('bookmarks')
597 def bookmarks(web, req, tmpl):
597 def bookmarks(web, req, tmpl):
598 """
598 """
599 /bookmarks
599 /bookmarks
600 ----------
600 ----------
601
601
602 Show information about bookmarks.
602 Show information about bookmarks.
603
603
604 No arguments are accepted.
604 No arguments are accepted.
605
605
606 The ``bookmarks`` template is rendered.
606 The ``bookmarks`` template is rendered.
607 """
607 """
608 i = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
608 i = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
609 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
609 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
610 i = sorted(i, key=sortkey, reverse=True)
610 i = sorted(i, key=sortkey, reverse=True)
611 parity = paritygen(web.stripecount)
611 parity = paritygen(web.stripecount)
612
612
613 def entries(latestonly, **map):
613 def entries(latestonly, **map):
614 t = i
614 t = i
615 if latestonly:
615 if latestonly:
616 t = i[:1]
616 t = i[:1]
617 for k, n in t:
617 for k, n in t:
618 yield {"parity": next(parity),
618 yield {"parity": next(parity),
619 "bookmark": k,
619 "bookmark": k,
620 "date": web.repo[n].date(),
620 "date": web.repo[n].date(),
621 "node": hex(n)}
621 "node": hex(n)}
622
622
623 if i:
623 if i:
624 latestrev = i[0][1]
624 latestrev = i[0][1]
625 else:
625 else:
626 latestrev = -1
626 latestrev = -1
627
627
628 return tmpl("bookmarks",
628 return tmpl("bookmarks",
629 node=hex(web.repo.changelog.tip()),
629 node=hex(web.repo.changelog.tip()),
630 lastchange=[{"date": web.repo[latestrev].date()}],
630 lastchange=[{"date": web.repo[latestrev].date()}],
631 entries=lambda **x: entries(latestonly=False, **x),
631 entries=lambda **x: entries(latestonly=False, **x),
632 latestentry=lambda **x: entries(latestonly=True, **x))
632 latestentry=lambda **x: entries(latestonly=True, **x))
633
633
634 @webcommand('branches')
634 @webcommand('branches')
635 def branches(web, req, tmpl):
635 def branches(web, req, tmpl):
636 """
636 """
637 /branches
637 /branches
638 ---------
638 ---------
639
639
640 Show information about branches.
640 Show information about branches.
641
641
642 All known branches are contained in the output, even closed branches.
642 All known branches are contained in the output, even closed branches.
643
643
644 No arguments are accepted.
644 No arguments are accepted.
645
645
646 The ``branches`` template is rendered.
646 The ``branches`` template is rendered.
647 """
647 """
648 entries = webutil.branchentries(web.repo, web.stripecount)
648 entries = webutil.branchentries(web.repo, web.stripecount)
649 latestentry = webutil.branchentries(web.repo, web.stripecount, 1)
649 latestentry = webutil.branchentries(web.repo, web.stripecount, 1)
650 return tmpl('branches', node=hex(web.repo.changelog.tip()),
650 return tmpl('branches', node=hex(web.repo.changelog.tip()),
651 entries=entries, latestentry=latestentry)
651 entries=entries, latestentry=latestentry)
652
652
653 @webcommand('summary')
653 @webcommand('summary')
654 def summary(web, req, tmpl):
654 def summary(web, req, tmpl):
655 """
655 """
656 /summary
656 /summary
657 --------
657 --------
658
658
659 Show a summary of repository state.
659 Show a summary of repository state.
660
660
661 Information about the latest changesets, bookmarks, tags, and branches
661 Information about the latest changesets, bookmarks, tags, and branches
662 is captured by this handler.
662 is captured by this handler.
663
663
664 The ``summary`` template is rendered.
664 The ``summary`` template is rendered.
665 """
665 """
666 i = reversed(web.repo.tagslist())
666 i = reversed(web.repo.tagslist())
667
667
668 def tagentries(**map):
668 def tagentries(**map):
669 parity = paritygen(web.stripecount)
669 parity = paritygen(web.stripecount)
670 count = 0
670 count = 0
671 for k, n in i:
671 for k, n in i:
672 if k == "tip": # skip tip
672 if k == "tip": # skip tip
673 continue
673 continue
674
674
675 count += 1
675 count += 1
676 if count > 10: # limit to 10 tags
676 if count > 10: # limit to 10 tags
677 break
677 break
678
678
679 yield tmpl("tagentry",
679 yield tmpl("tagentry",
680 parity=next(parity),
680 parity=next(parity),
681 tag=k,
681 tag=k,
682 node=hex(n),
682 node=hex(n),
683 date=web.repo[n].date())
683 date=web.repo[n].date())
684
684
685 def bookmarks(**map):
685 def bookmarks(**map):
686 parity = paritygen(web.stripecount)
686 parity = paritygen(web.stripecount)
687 marks = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
687 marks = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
688 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
688 sortkey = lambda b: (web.repo[b[1]].rev(), b[0])
689 marks = sorted(marks, key=sortkey, reverse=True)
689 marks = sorted(marks, key=sortkey, reverse=True)
690 for k, n in marks[:10]: # limit to 10 bookmarks
690 for k, n in marks[:10]: # limit to 10 bookmarks
691 yield {'parity': next(parity),
691 yield {'parity': next(parity),
692 'bookmark': k,
692 'bookmark': k,
693 'date': web.repo[n].date(),
693 'date': web.repo[n].date(),
694 'node': hex(n)}
694 'node': hex(n)}
695
695
696 def changelist(**map):
696 def changelist(**map):
697 parity = paritygen(web.stripecount, offset=start - end)
697 parity = paritygen(web.stripecount, offset=start - end)
698 l = [] # build a list in forward order for efficiency
698 l = [] # build a list in forward order for efficiency
699 revs = []
699 revs = []
700 if start < end:
700 if start < end:
701 revs = web.repo.changelog.revs(start, end - 1)
701 revs = web.repo.changelog.revs(start, end - 1)
702 for i in revs:
702 for i in revs:
703 ctx = web.repo[i]
703 ctx = web.repo[i]
704
704
705 l.append(tmpl(
705 l.append(tmpl(
706 'shortlogentry',
706 'shortlogentry',
707 parity=next(parity),
707 parity=next(parity),
708 **webutil.commonentry(web.repo, ctx)))
708 **webutil.commonentry(web.repo, ctx)))
709
709
710 for entry in reversed(l):
710 for entry in reversed(l):
711 yield entry
711 yield entry
712
712
713 tip = web.repo['tip']
713 tip = web.repo['tip']
714 count = len(web.repo)
714 count = len(web.repo)
715 start = max(0, count - web.maxchanges)
715 start = max(0, count - web.maxchanges)
716 end = min(count, start + web.maxchanges)
716 end = min(count, start + web.maxchanges)
717
717
718 return tmpl("summary",
718 return tmpl("summary",
719 desc=web.config("web", "description", "unknown"),
719 desc=web.config("web", "description", "unknown"),
720 owner=get_contact(web.config) or "unknown",
720 owner=get_contact(web.config) or "unknown",
721 lastchange=tip.date(),
721 lastchange=tip.date(),
722 tags=tagentries,
722 tags=tagentries,
723 bookmarks=bookmarks,
723 bookmarks=bookmarks,
724 branches=webutil.branchentries(web.repo, web.stripecount, 10),
724 branches=webutil.branchentries(web.repo, web.stripecount, 10),
725 shortlog=changelist,
725 shortlog=changelist,
726 node=tip.hex(),
726 node=tip.hex(),
727 symrev='tip',
727 symrev='tip',
728 archives=web.archivelist("tip"))
728 archives=web.archivelist("tip"))
729
729
730 @webcommand('filediff')
730 @webcommand('filediff')
731 def filediff(web, req, tmpl):
731 def filediff(web, req, tmpl):
732 """
732 """
733 /diff/{revision}/{path}
733 /diff/{revision}/{path}
734 -----------------------
734 -----------------------
735
735
736 Show how a file changed in a particular commit.
736 Show how a file changed in a particular commit.
737
737
738 The ``filediff`` template is rendered.
738 The ``filediff`` template is rendered.
739
739
740 This handler is registered under both the ``/diff`` and ``/filediff``
740 This handler is registered under both the ``/diff`` and ``/filediff``
741 paths. ``/diff`` is used in modern code.
741 paths. ``/diff`` is used in modern code.
742 """
742 """
743 fctx, ctx = None, None
743 fctx, ctx = None, None
744 try:
744 try:
745 fctx = webutil.filectx(web.repo, req)
745 fctx = webutil.filectx(web.repo, req)
746 except LookupError:
746 except LookupError:
747 ctx = webutil.changectx(web.repo, req)
747 ctx = webutil.changectx(web.repo, req)
748 path = webutil.cleanpath(web.repo, req.form['file'][0])
748 path = webutil.cleanpath(web.repo, req.form['file'][0])
749 if path not in ctx.files():
749 if path not in ctx.files():
750 raise
750 raise
751
751
752 if fctx is not None:
752 if fctx is not None:
753 path = fctx.path()
753 path = fctx.path()
754 ctx = fctx.changectx()
754 ctx = fctx.changectx()
755
755
756 parity = paritygen(web.stripecount)
756 parity = paritygen(web.stripecount)
757 style = web.config('web', 'style', 'paper')
757 style = web.config('web', 'style', 'paper')
758 if 'style' in req.form:
758 if 'style' in req.form:
759 style = req.form['style'][0]
759 style = req.form['style'][0]
760
760
761 diffs = webutil.diffs(web.repo, tmpl, ctx, None, [path], parity, style)
761 diffs = webutil.diffs(web.repo, tmpl, ctx, None, [path], parity, style)
762 if fctx is not None:
762 if fctx is not None:
763 rename = webutil.renamelink(fctx)
763 rename = webutil.renamelink(fctx)
764 ctx = fctx
764 ctx = fctx
765 else:
765 else:
766 rename = []
766 rename = []
767 ctx = ctx
767 ctx = ctx
768 return tmpl("filediff",
768 return tmpl("filediff",
769 file=path,
769 file=path,
770 symrev=webutil.symrevorshortnode(req, ctx),
770 symrev=webutil.symrevorshortnode(req, ctx),
771 rename=rename,
771 rename=rename,
772 diff=diffs,
772 diff=diffs,
773 **webutil.commonentry(web.repo, ctx))
773 **webutil.commonentry(web.repo, ctx))
774
774
775 diff = webcommand('diff')(filediff)
775 diff = webcommand('diff')(filediff)
776
776
777 @webcommand('comparison')
777 @webcommand('comparison')
778 def comparison(web, req, tmpl):
778 def comparison(web, req, tmpl):
779 """
779 """
780 /comparison/{revision}/{path}
780 /comparison/{revision}/{path}
781 -----------------------------
781 -----------------------------
782
782
783 Show a comparison between the old and new versions of a file from changes
783 Show a comparison between the old and new versions of a file from changes
784 made on a particular revision.
784 made on a particular revision.
785
785
786 This is similar to the ``diff`` handler. However, this form features
786 This is similar to the ``diff`` handler. However, this form features
787 a split or side-by-side diff rather than a unified diff.
787 a split or side-by-side diff rather than a unified diff.
788
788
789 The ``context`` query string argument can be used to control the lines of
789 The ``context`` query string argument can be used to control the lines of
790 context in the diff.
790 context in the diff.
791
791
792 The ``filecomparison`` template is rendered.
792 The ``filecomparison`` template is rendered.
793 """
793 """
794 ctx = webutil.changectx(web.repo, req)
794 ctx = webutil.changectx(web.repo, req)
795 if 'file' not in req.form:
795 if 'file' not in req.form:
796 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
796 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
797 path = webutil.cleanpath(web.repo, req.form['file'][0])
797 path = webutil.cleanpath(web.repo, req.form['file'][0])
798
798
799 parsecontext = lambda v: v == 'full' and -1 or int(v)
799 parsecontext = lambda v: v == 'full' and -1 or int(v)
800 if 'context' in req.form:
800 if 'context' in req.form:
801 context = parsecontext(req.form['context'][0])
801 context = parsecontext(req.form['context'][0])
802 else:
802 else:
803 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
803 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
804
804
805 def filelines(f):
805 def filelines(f):
806 if util.binary(f.data()):
806 if util.binary(f.data()):
807 mt = mimetypes.guess_type(f.path())[0]
807 mt = mimetypes.guess_type(f.path())[0]
808 if not mt:
808 if not mt:
809 mt = 'application/octet-stream'
809 mt = 'application/octet-stream'
810 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
810 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
811 return f.data().splitlines()
811 return f.data().splitlines()
812
812
813 fctx = None
813 fctx = None
814 parent = ctx.p1()
814 parent = ctx.p1()
815 leftrev = parent.rev()
815 leftrev = parent.rev()
816 leftnode = parent.node()
816 leftnode = parent.node()
817 rightrev = ctx.rev()
817 rightrev = ctx.rev()
818 rightnode = ctx.node()
818 rightnode = ctx.node()
819 if path in ctx:
819 if path in ctx:
820 fctx = ctx[path]
820 fctx = ctx[path]
821 rightlines = filelines(fctx)
821 rightlines = filelines(fctx)
822 if path not in parent:
822 if path not in parent:
823 leftlines = ()
823 leftlines = ()
824 else:
824 else:
825 pfctx = parent[path]
825 pfctx = parent[path]
826 leftlines = filelines(pfctx)
826 leftlines = filelines(pfctx)
827 else:
827 else:
828 rightlines = ()
828 rightlines = ()
829 pfctx = ctx.parents()[0][path]
829 pfctx = ctx.parents()[0][path]
830 leftlines = filelines(pfctx)
830 leftlines = filelines(pfctx)
831
831
832 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
832 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
833 if fctx is not None:
833 if fctx is not None:
834 rename = webutil.renamelink(fctx)
834 rename = webutil.renamelink(fctx)
835 ctx = fctx
835 ctx = fctx
836 else:
836 else:
837 rename = []
837 rename = []
838 ctx = ctx
838 ctx = ctx
839 return tmpl('filecomparison',
839 return tmpl('filecomparison',
840 file=path,
840 file=path,
841 symrev=webutil.symrevorshortnode(req, ctx),
841 symrev=webutil.symrevorshortnode(req, ctx),
842 rename=rename,
842 rename=rename,
843 leftrev=leftrev,
843 leftrev=leftrev,
844 leftnode=hex(leftnode),
844 leftnode=hex(leftnode),
845 rightrev=rightrev,
845 rightrev=rightrev,
846 rightnode=hex(rightnode),
846 rightnode=hex(rightnode),
847 comparison=comparison,
847 comparison=comparison,
848 **webutil.commonentry(web.repo, ctx))
848 **webutil.commonentry(web.repo, ctx))
849
849
850 @webcommand('annotate')
850 @webcommand('annotate')
851 def annotate(web, req, tmpl):
851 def annotate(web, req, tmpl):
852 """
852 """
853 /annotate/{revision}/{path}
853 /annotate/{revision}/{path}
854 ---------------------------
854 ---------------------------
855
855
856 Show changeset information for each line in a file.
856 Show changeset information for each line in a file.
857
857
858 The ``fileannotate`` template is rendered.
858 The ``fileannotate`` template is rendered.
859 """
859 """
860 fctx = webutil.filectx(web.repo, req)
860 fctx = webutil.filectx(web.repo, req)
861 f = fctx.path()
861 f = fctx.path()
862 parity = paritygen(web.stripecount)
862 parity = paritygen(web.stripecount)
863 diffopts = patch.difffeatureopts(web.repo.ui, untrusted=True,
863 diffopts = patch.difffeatureopts(web.repo.ui, untrusted=True,
864 section='annotate', whitespace=True)
864 section='annotate', whitespace=True)
865
865
866 def annotate(**map):
866 def annotate(**map):
867 if util.binary(fctx.data()):
867 if util.binary(fctx.data()):
868 mt = (mimetypes.guess_type(fctx.path())[0]
868 mt = (mimetypes.guess_type(fctx.path())[0]
869 or 'application/octet-stream')
869 or 'application/octet-stream')
870 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
870 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
871 '(binary:%s)' % mt)])
871 '(binary:%s)' % mt)])
872 else:
872 else:
873 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
873 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
874 diffopts=diffopts))
874 diffopts=diffopts))
875 previousrev = None
875 for lineno, ((f, targetline), l) in lines:
876 for lineno, ((f, targetline), l) in lines:
877 rev = f.rev()
878 blockhead = rev != previousrev or None
879 previousrev = rev
876 yield {"parity": next(parity),
880 yield {"parity": next(parity),
877 "node": f.hex(),
881 "node": f.hex(),
878 "rev": f.rev(),
882 "rev": rev,
879 "author": f.user(),
883 "author": f.user(),
880 "desc": f.description(),
884 "desc": f.description(),
881 "extra": f.extra(),
885 "extra": f.extra(),
882 "file": f.path(),
886 "file": f.path(),
887 "blockhead": blockhead,
883 "targetline": targetline,
888 "targetline": targetline,
884 "line": l,
889 "line": l,
885 "lineno": lineno + 1,
890 "lineno": lineno + 1,
886 "lineid": "l%d" % (lineno + 1),
891 "lineid": "l%d" % (lineno + 1),
887 "linenumber": "% 6d" % (lineno + 1),
892 "linenumber": "% 6d" % (lineno + 1),
888 "revdate": f.date()}
893 "revdate": f.date()}
889
894
890 return tmpl("fileannotate",
895 return tmpl("fileannotate",
891 file=f,
896 file=f,
892 annotate=annotate,
897 annotate=annotate,
893 path=webutil.up(f),
898 path=webutil.up(f),
894 symrev=webutil.symrevorshortnode(req, fctx),
899 symrev=webutil.symrevorshortnode(req, fctx),
895 rename=webutil.renamelink(fctx),
900 rename=webutil.renamelink(fctx),
896 permissions=fctx.manifest().flags(f),
901 permissions=fctx.manifest().flags(f),
897 **webutil.commonentry(web.repo, fctx))
902 **webutil.commonentry(web.repo, fctx))
898
903
899 @webcommand('filelog')
904 @webcommand('filelog')
900 def filelog(web, req, tmpl):
905 def filelog(web, req, tmpl):
901 """
906 """
902 /filelog/{revision}/{path}
907 /filelog/{revision}/{path}
903 --------------------------
908 --------------------------
904
909
905 Show information about the history of a file in the repository.
910 Show information about the history of a file in the repository.
906
911
907 The ``revcount`` query string argument can be defined to control the
912 The ``revcount`` query string argument can be defined to control the
908 maximum number of entries to show.
913 maximum number of entries to show.
909
914
910 The ``filelog`` template will be rendered.
915 The ``filelog`` template will be rendered.
911 """
916 """
912
917
913 try:
918 try:
914 fctx = webutil.filectx(web.repo, req)
919 fctx = webutil.filectx(web.repo, req)
915 f = fctx.path()
920 f = fctx.path()
916 fl = fctx.filelog()
921 fl = fctx.filelog()
917 except error.LookupError:
922 except error.LookupError:
918 f = webutil.cleanpath(web.repo, req.form['file'][0])
923 f = webutil.cleanpath(web.repo, req.form['file'][0])
919 fl = web.repo.file(f)
924 fl = web.repo.file(f)
920 numrevs = len(fl)
925 numrevs = len(fl)
921 if not numrevs: # file doesn't exist at all
926 if not numrevs: # file doesn't exist at all
922 raise
927 raise
923 rev = webutil.changectx(web.repo, req).rev()
928 rev = webutil.changectx(web.repo, req).rev()
924 first = fl.linkrev(0)
929 first = fl.linkrev(0)
925 if rev < first: # current rev is from before file existed
930 if rev < first: # current rev is from before file existed
926 raise
931 raise
927 frev = numrevs - 1
932 frev = numrevs - 1
928 while fl.linkrev(frev) > rev:
933 while fl.linkrev(frev) > rev:
929 frev -= 1
934 frev -= 1
930 fctx = web.repo.filectx(f, fl.linkrev(frev))
935 fctx = web.repo.filectx(f, fl.linkrev(frev))
931
936
932 revcount = web.maxshortchanges
937 revcount = web.maxshortchanges
933 if 'revcount' in req.form:
938 if 'revcount' in req.form:
934 try:
939 try:
935 revcount = int(req.form.get('revcount', [revcount])[0])
940 revcount = int(req.form.get('revcount', [revcount])[0])
936 revcount = max(revcount, 1)
941 revcount = max(revcount, 1)
937 tmpl.defaults['sessionvars']['revcount'] = revcount
942 tmpl.defaults['sessionvars']['revcount'] = revcount
938 except ValueError:
943 except ValueError:
939 pass
944 pass
940
945
941 lessvars = copy.copy(tmpl.defaults['sessionvars'])
946 lessvars = copy.copy(tmpl.defaults['sessionvars'])
942 lessvars['revcount'] = max(revcount / 2, 1)
947 lessvars['revcount'] = max(revcount / 2, 1)
943 morevars = copy.copy(tmpl.defaults['sessionvars'])
948 morevars = copy.copy(tmpl.defaults['sessionvars'])
944 morevars['revcount'] = revcount * 2
949 morevars['revcount'] = revcount * 2
945
950
946 count = fctx.filerev() + 1
951 count = fctx.filerev() + 1
947 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
952 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
948 end = min(count, start + revcount) # last rev on this page
953 end = min(count, start + revcount) # last rev on this page
949 parity = paritygen(web.stripecount, offset=start - end)
954 parity = paritygen(web.stripecount, offset=start - end)
950
955
951 def entries():
956 def entries():
952 l = []
957 l = []
953
958
954 repo = web.repo
959 repo = web.repo
955 revs = fctx.filelog().revs(start, end - 1)
960 revs = fctx.filelog().revs(start, end - 1)
956 for i in revs:
961 for i in revs:
957 iterfctx = fctx.filectx(i)
962 iterfctx = fctx.filectx(i)
958
963
959 l.append(dict(
964 l.append(dict(
960 parity=next(parity),
965 parity=next(parity),
961 filerev=i,
966 filerev=i,
962 file=f,
967 file=f,
963 rename=webutil.renamelink(iterfctx),
968 rename=webutil.renamelink(iterfctx),
964 **webutil.commonentry(repo, iterfctx)))
969 **webutil.commonentry(repo, iterfctx)))
965 for e in reversed(l):
970 for e in reversed(l):
966 yield e
971 yield e
967
972
968 entries = list(entries())
973 entries = list(entries())
969 latestentry = entries[:1]
974 latestentry = entries[:1]
970
975
971 revnav = webutil.filerevnav(web.repo, fctx.path())
976 revnav = webutil.filerevnav(web.repo, fctx.path())
972 nav = revnav.gen(end - 1, revcount, count)
977 nav = revnav.gen(end - 1, revcount, count)
973 return tmpl("filelog",
978 return tmpl("filelog",
974 file=f,
979 file=f,
975 nav=nav,
980 nav=nav,
976 symrev=webutil.symrevorshortnode(req, fctx),
981 symrev=webutil.symrevorshortnode(req, fctx),
977 entries=entries,
982 entries=entries,
978 latestentry=latestentry,
983 latestentry=latestentry,
979 revcount=revcount,
984 revcount=revcount,
980 morevars=morevars,
985 morevars=morevars,
981 lessvars=lessvars,
986 lessvars=lessvars,
982 **webutil.commonentry(web.repo, fctx))
987 **webutil.commonentry(web.repo, fctx))
983
988
984 @webcommand('archive')
989 @webcommand('archive')
985 def archive(web, req, tmpl):
990 def archive(web, req, tmpl):
986 """
991 """
987 /archive/{revision}.{format}[/{path}]
992 /archive/{revision}.{format}[/{path}]
988 -------------------------------------
993 -------------------------------------
989
994
990 Obtain an archive of repository content.
995 Obtain an archive of repository content.
991
996
992 The content and type of the archive is defined by a URL path parameter.
997 The content and type of the archive is defined by a URL path parameter.
993 ``format`` is the file extension of the archive type to be generated. e.g.
998 ``format`` is the file extension of the archive type to be generated. e.g.
994 ``zip`` or ``tar.bz2``. Not all archive types may be allowed by your
999 ``zip`` or ``tar.bz2``. Not all archive types may be allowed by your
995 server configuration.
1000 server configuration.
996
1001
997 The optional ``path`` URL parameter controls content to include in the
1002 The optional ``path`` URL parameter controls content to include in the
998 archive. If omitted, every file in the specified revision is present in the
1003 archive. If omitted, every file in the specified revision is present in the
999 archive. If included, only the specified file or contents of the specified
1004 archive. If included, only the specified file or contents of the specified
1000 directory will be included in the archive.
1005 directory will be included in the archive.
1001
1006
1002 No template is used for this handler. Raw, binary content is generated.
1007 No template is used for this handler. Raw, binary content is generated.
1003 """
1008 """
1004
1009
1005 type_ = req.form.get('type', [None])[0]
1010 type_ = req.form.get('type', [None])[0]
1006 allowed = web.configlist("web", "allow_archive")
1011 allowed = web.configlist("web", "allow_archive")
1007 key = req.form['node'][0]
1012 key = req.form['node'][0]
1008
1013
1009 if type_ not in web.archives:
1014 if type_ not in web.archives:
1010 msg = 'Unsupported archive type: %s' % type_
1015 msg = 'Unsupported archive type: %s' % type_
1011 raise ErrorResponse(HTTP_NOT_FOUND, msg)
1016 raise ErrorResponse(HTTP_NOT_FOUND, msg)
1012
1017
1013 if not ((type_ in allowed or
1018 if not ((type_ in allowed or
1014 web.configbool("web", "allow" + type_, False))):
1019 web.configbool("web", "allow" + type_, False))):
1015 msg = 'Archive type not allowed: %s' % type_
1020 msg = 'Archive type not allowed: %s' % type_
1016 raise ErrorResponse(HTTP_FORBIDDEN, msg)
1021 raise ErrorResponse(HTTP_FORBIDDEN, msg)
1017
1022
1018 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
1023 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
1019 cnode = web.repo.lookup(key)
1024 cnode = web.repo.lookup(key)
1020 arch_version = key
1025 arch_version = key
1021 if cnode == key or key == 'tip':
1026 if cnode == key or key == 'tip':
1022 arch_version = short(cnode)
1027 arch_version = short(cnode)
1023 name = "%s-%s" % (reponame, arch_version)
1028 name = "%s-%s" % (reponame, arch_version)
1024
1029
1025 ctx = webutil.changectx(web.repo, req)
1030 ctx = webutil.changectx(web.repo, req)
1026 pats = []
1031 pats = []
1027 matchfn = scmutil.match(ctx, [])
1032 matchfn = scmutil.match(ctx, [])
1028 file = req.form.get('file', None)
1033 file = req.form.get('file', None)
1029 if file:
1034 if file:
1030 pats = ['path:' + file[0]]
1035 pats = ['path:' + file[0]]
1031 matchfn = scmutil.match(ctx, pats, default='path')
1036 matchfn = scmutil.match(ctx, pats, default='path')
1032 if pats:
1037 if pats:
1033 files = [f for f in ctx.manifest().keys() if matchfn(f)]
1038 files = [f for f in ctx.manifest().keys() if matchfn(f)]
1034 if not files:
1039 if not files:
1035 raise ErrorResponse(HTTP_NOT_FOUND,
1040 raise ErrorResponse(HTTP_NOT_FOUND,
1036 'file(s) not found: %s' % file[0])
1041 'file(s) not found: %s' % file[0])
1037
1042
1038 mimetype, artype, extension, encoding = web.archivespecs[type_]
1043 mimetype, artype, extension, encoding = web.archivespecs[type_]
1039 headers = [
1044 headers = [
1040 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
1045 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
1041 ]
1046 ]
1042 if encoding:
1047 if encoding:
1043 headers.append(('Content-Encoding', encoding))
1048 headers.append(('Content-Encoding', encoding))
1044 req.headers.extend(headers)
1049 req.headers.extend(headers)
1045 req.respond(HTTP_OK, mimetype)
1050 req.respond(HTTP_OK, mimetype)
1046
1051
1047 archival.archive(web.repo, req, cnode, artype, prefix=name,
1052 archival.archive(web.repo, req, cnode, artype, prefix=name,
1048 matchfn=matchfn,
1053 matchfn=matchfn,
1049 subrepos=web.configbool("web", "archivesubrepos"))
1054 subrepos=web.configbool("web", "archivesubrepos"))
1050 return []
1055 return []
1051
1056
1052
1057
1053 @webcommand('static')
1058 @webcommand('static')
1054 def static(web, req, tmpl):
1059 def static(web, req, tmpl):
1055 fname = req.form['file'][0]
1060 fname = req.form['file'][0]
1056 # a repo owner may set web.static in .hg/hgrc to get any file
1061 # a repo owner may set web.static in .hg/hgrc to get any file
1057 # readable by the user running the CGI script
1062 # readable by the user running the CGI script
1058 static = web.config("web", "static", None, untrusted=False)
1063 static = web.config("web", "static", None, untrusted=False)
1059 if not static:
1064 if not static:
1060 tp = web.templatepath or templater.templatepaths()
1065 tp = web.templatepath or templater.templatepaths()
1061 if isinstance(tp, str):
1066 if isinstance(tp, str):
1062 tp = [tp]
1067 tp = [tp]
1063 static = [os.path.join(p, 'static') for p in tp]
1068 static = [os.path.join(p, 'static') for p in tp]
1064 staticfile(static, fname, req)
1069 staticfile(static, fname, req)
1065 return []
1070 return []
1066
1071
1067 @webcommand('graph')
1072 @webcommand('graph')
1068 def graph(web, req, tmpl):
1073 def graph(web, req, tmpl):
1069 """
1074 """
1070 /graph[/{revision}]
1075 /graph[/{revision}]
1071 -------------------
1076 -------------------
1072
1077
1073 Show information about the graphical topology of the repository.
1078 Show information about the graphical topology of the repository.
1074
1079
1075 Information rendered by this handler can be used to create visual
1080 Information rendered by this handler can be used to create visual
1076 representations of repository topology.
1081 representations of repository topology.
1077
1082
1078 The ``revision`` URL parameter controls the starting changeset.
1083 The ``revision`` URL parameter controls the starting changeset.
1079
1084
1080 The ``revcount`` query string argument can define the number of changesets
1085 The ``revcount`` query string argument can define the number of changesets
1081 to show information for.
1086 to show information for.
1082
1087
1083 This handler will render the ``graph`` template.
1088 This handler will render the ``graph`` template.
1084 """
1089 """
1085
1090
1086 if 'node' in req.form:
1091 if 'node' in req.form:
1087 ctx = webutil.changectx(web.repo, req)
1092 ctx = webutil.changectx(web.repo, req)
1088 symrev = webutil.symrevorshortnode(req, ctx)
1093 symrev = webutil.symrevorshortnode(req, ctx)
1089 else:
1094 else:
1090 ctx = web.repo['tip']
1095 ctx = web.repo['tip']
1091 symrev = 'tip'
1096 symrev = 'tip'
1092 rev = ctx.rev()
1097 rev = ctx.rev()
1093
1098
1094 bg_height = 39
1099 bg_height = 39
1095 revcount = web.maxshortchanges
1100 revcount = web.maxshortchanges
1096 if 'revcount' in req.form:
1101 if 'revcount' in req.form:
1097 try:
1102 try:
1098 revcount = int(req.form.get('revcount', [revcount])[0])
1103 revcount = int(req.form.get('revcount', [revcount])[0])
1099 revcount = max(revcount, 1)
1104 revcount = max(revcount, 1)
1100 tmpl.defaults['sessionvars']['revcount'] = revcount
1105 tmpl.defaults['sessionvars']['revcount'] = revcount
1101 except ValueError:
1106 except ValueError:
1102 pass
1107 pass
1103
1108
1104 lessvars = copy.copy(tmpl.defaults['sessionvars'])
1109 lessvars = copy.copy(tmpl.defaults['sessionvars'])
1105 lessvars['revcount'] = max(revcount / 2, 1)
1110 lessvars['revcount'] = max(revcount / 2, 1)
1106 morevars = copy.copy(tmpl.defaults['sessionvars'])
1111 morevars = copy.copy(tmpl.defaults['sessionvars'])
1107 morevars['revcount'] = revcount * 2
1112 morevars['revcount'] = revcount * 2
1108
1113
1109 count = len(web.repo)
1114 count = len(web.repo)
1110 pos = rev
1115 pos = rev
1111
1116
1112 uprev = min(max(0, count - 1), rev + revcount)
1117 uprev = min(max(0, count - 1), rev + revcount)
1113 downrev = max(0, rev - revcount)
1118 downrev = max(0, rev - revcount)
1114 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
1119 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
1115
1120
1116 tree = []
1121 tree = []
1117 if pos != -1:
1122 if pos != -1:
1118 allrevs = web.repo.changelog.revs(pos, 0)
1123 allrevs = web.repo.changelog.revs(pos, 0)
1119 revs = []
1124 revs = []
1120 for i in allrevs:
1125 for i in allrevs:
1121 revs.append(i)
1126 revs.append(i)
1122 if len(revs) >= revcount:
1127 if len(revs) >= revcount:
1123 break
1128 break
1124
1129
1125 # We have to feed a baseset to dagwalker as it is expecting smartset
1130 # We have to feed a baseset to dagwalker as it is expecting smartset
1126 # object. This does not have a big impact on hgweb performance itself
1131 # object. This does not have a big impact on hgweb performance itself
1127 # since hgweb graphing code is not itself lazy yet.
1132 # since hgweb graphing code is not itself lazy yet.
1128 dag = graphmod.dagwalker(web.repo, revset.baseset(revs))
1133 dag = graphmod.dagwalker(web.repo, revset.baseset(revs))
1129 # As we said one line above... not lazy.
1134 # As we said one line above... not lazy.
1130 tree = list(graphmod.colored(dag, web.repo))
1135 tree = list(graphmod.colored(dag, web.repo))
1131
1136
1132 def getcolumns(tree):
1137 def getcolumns(tree):
1133 cols = 0
1138 cols = 0
1134 for (id, type, ctx, vtx, edges) in tree:
1139 for (id, type, ctx, vtx, edges) in tree:
1135 if type != graphmod.CHANGESET:
1140 if type != graphmod.CHANGESET:
1136 continue
1141 continue
1137 cols = max(cols, max([edge[0] for edge in edges] or [0]),
1142 cols = max(cols, max([edge[0] for edge in edges] or [0]),
1138 max([edge[1] for edge in edges] or [0]))
1143 max([edge[1] for edge in edges] or [0]))
1139 return cols
1144 return cols
1140
1145
1141 def graphdata(usetuples, encodestr):
1146 def graphdata(usetuples, encodestr):
1142 data = []
1147 data = []
1143
1148
1144 row = 0
1149 row = 0
1145 for (id, type, ctx, vtx, edges) in tree:
1150 for (id, type, ctx, vtx, edges) in tree:
1146 if type != graphmod.CHANGESET:
1151 if type != graphmod.CHANGESET:
1147 continue
1152 continue
1148 node = str(ctx)
1153 node = str(ctx)
1149 age = encodestr(templatefilters.age(ctx.date()))
1154 age = encodestr(templatefilters.age(ctx.date()))
1150 desc = templatefilters.firstline(encodestr(ctx.description()))
1155 desc = templatefilters.firstline(encodestr(ctx.description()))
1151 desc = cgi.escape(templatefilters.nonempty(desc))
1156 desc = cgi.escape(templatefilters.nonempty(desc))
1152 user = cgi.escape(templatefilters.person(encodestr(ctx.user())))
1157 user = cgi.escape(templatefilters.person(encodestr(ctx.user())))
1153 branch = cgi.escape(encodestr(ctx.branch()))
1158 branch = cgi.escape(encodestr(ctx.branch()))
1154 try:
1159 try:
1155 branchnode = web.repo.branchtip(branch)
1160 branchnode = web.repo.branchtip(branch)
1156 except error.RepoLookupError:
1161 except error.RepoLookupError:
1157 branchnode = None
1162 branchnode = None
1158 branch = branch, branchnode == ctx.node()
1163 branch = branch, branchnode == ctx.node()
1159
1164
1160 if usetuples:
1165 if usetuples:
1161 data.append((node, vtx, edges, desc, user, age, branch,
1166 data.append((node, vtx, edges, desc, user, age, branch,
1162 [cgi.escape(encodestr(x)) for x in ctx.tags()],
1167 [cgi.escape(encodestr(x)) for x in ctx.tags()],
1163 [cgi.escape(encodestr(x))
1168 [cgi.escape(encodestr(x))
1164 for x in ctx.bookmarks()]))
1169 for x in ctx.bookmarks()]))
1165 else:
1170 else:
1166 edgedata = [{'col': edge[0], 'nextcol': edge[1],
1171 edgedata = [{'col': edge[0], 'nextcol': edge[1],
1167 'color': (edge[2] - 1) % 6 + 1,
1172 'color': (edge[2] - 1) % 6 + 1,
1168 'width': edge[3], 'bcolor': edge[4]}
1173 'width': edge[3], 'bcolor': edge[4]}
1169 for edge in edges]
1174 for edge in edges]
1170
1175
1171 data.append(
1176 data.append(
1172 {'node': node,
1177 {'node': node,
1173 'col': vtx[0],
1178 'col': vtx[0],
1174 'color': (vtx[1] - 1) % 6 + 1,
1179 'color': (vtx[1] - 1) % 6 + 1,
1175 'edges': edgedata,
1180 'edges': edgedata,
1176 'row': row,
1181 'row': row,
1177 'nextrow': row + 1,
1182 'nextrow': row + 1,
1178 'desc': desc,
1183 'desc': desc,
1179 'user': user,
1184 'user': user,
1180 'age': age,
1185 'age': age,
1181 'bookmarks': webutil.nodebookmarksdict(
1186 'bookmarks': webutil.nodebookmarksdict(
1182 web.repo, ctx.node()),
1187 web.repo, ctx.node()),
1183 'branches': webutil.nodebranchdict(web.repo, ctx),
1188 'branches': webutil.nodebranchdict(web.repo, ctx),
1184 'inbranch': webutil.nodeinbranch(web.repo, ctx),
1189 'inbranch': webutil.nodeinbranch(web.repo, ctx),
1185 'tags': webutil.nodetagsdict(web.repo, ctx.node())})
1190 'tags': webutil.nodetagsdict(web.repo, ctx.node())})
1186
1191
1187 row += 1
1192 row += 1
1188
1193
1189 return data
1194 return data
1190
1195
1191 cols = getcolumns(tree)
1196 cols = getcolumns(tree)
1192 rows = len(tree)
1197 rows = len(tree)
1193 canvasheight = (rows + 1) * bg_height - 27
1198 canvasheight = (rows + 1) * bg_height - 27
1194
1199
1195 return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount,
1200 return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount,
1196 uprev=uprev,
1201 uprev=uprev,
1197 lessvars=lessvars, morevars=morevars, downrev=downrev,
1202 lessvars=lessvars, morevars=morevars, downrev=downrev,
1198 cols=cols, rows=rows,
1203 cols=cols, rows=rows,
1199 canvaswidth=(cols + 1) * bg_height,
1204 canvaswidth=(cols + 1) * bg_height,
1200 truecanvasheight=rows * bg_height,
1205 truecanvasheight=rows * bg_height,
1201 canvasheight=canvasheight, bg_height=bg_height,
1206 canvasheight=canvasheight, bg_height=bg_height,
1202 # {jsdata} will be passed to |json, so it must be in utf-8
1207 # {jsdata} will be passed to |json, so it must be in utf-8
1203 jsdata=lambda **x: graphdata(True, encoding.fromlocal),
1208 jsdata=lambda **x: graphdata(True, encoding.fromlocal),
1204 nodes=lambda **x: graphdata(False, str),
1209 nodes=lambda **x: graphdata(False, str),
1205 node=ctx.hex(), changenav=changenav)
1210 node=ctx.hex(), changenav=changenav)
1206
1211
1207 def _getdoc(e):
1212 def _getdoc(e):
1208 doc = e[0].__doc__
1213 doc = e[0].__doc__
1209 if doc:
1214 if doc:
1210 doc = _(doc).partition('\n')[0]
1215 doc = _(doc).partition('\n')[0]
1211 else:
1216 else:
1212 doc = _('(no help text available)')
1217 doc = _('(no help text available)')
1213 return doc
1218 return doc
1214
1219
1215 @webcommand('help')
1220 @webcommand('help')
1216 def help(web, req, tmpl):
1221 def help(web, req, tmpl):
1217 """
1222 """
1218 /help[/{topic}]
1223 /help[/{topic}]
1219 ---------------
1224 ---------------
1220
1225
1221 Render help documentation.
1226 Render help documentation.
1222
1227
1223 This web command is roughly equivalent to :hg:`help`. If a ``topic``
1228 This web command is roughly equivalent to :hg:`help`. If a ``topic``
1224 is defined, that help topic will be rendered. If not, an index of
1229 is defined, that help topic will be rendered. If not, an index of
1225 available help topics will be rendered.
1230 available help topics will be rendered.
1226
1231
1227 The ``help`` template will be rendered when requesting help for a topic.
1232 The ``help`` template will be rendered when requesting help for a topic.
1228 ``helptopics`` will be rendered for the index of help topics.
1233 ``helptopics`` will be rendered for the index of help topics.
1229 """
1234 """
1230 from .. import commands, help as helpmod # avoid cycle
1235 from .. import commands, help as helpmod # avoid cycle
1231
1236
1232 topicname = req.form.get('node', [None])[0]
1237 topicname = req.form.get('node', [None])[0]
1233 if not topicname:
1238 if not topicname:
1234 def topics(**map):
1239 def topics(**map):
1235 for entries, summary, _doc in helpmod.helptable:
1240 for entries, summary, _doc in helpmod.helptable:
1236 yield {'topic': entries[0], 'summary': summary}
1241 yield {'topic': entries[0], 'summary': summary}
1237
1242
1238 early, other = [], []
1243 early, other = [], []
1239 primary = lambda s: s.partition('|')[0]
1244 primary = lambda s: s.partition('|')[0]
1240 for c, e in commands.table.iteritems():
1245 for c, e in commands.table.iteritems():
1241 doc = _getdoc(e)
1246 doc = _getdoc(e)
1242 if 'DEPRECATED' in doc or c.startswith('debug'):
1247 if 'DEPRECATED' in doc or c.startswith('debug'):
1243 continue
1248 continue
1244 cmd = primary(c)
1249 cmd = primary(c)
1245 if cmd.startswith('^'):
1250 if cmd.startswith('^'):
1246 early.append((cmd[1:], doc))
1251 early.append((cmd[1:], doc))
1247 else:
1252 else:
1248 other.append((cmd, doc))
1253 other.append((cmd, doc))
1249
1254
1250 early.sort()
1255 early.sort()
1251 other.sort()
1256 other.sort()
1252
1257
1253 def earlycommands(**map):
1258 def earlycommands(**map):
1254 for c, doc in early:
1259 for c, doc in early:
1255 yield {'topic': c, 'summary': doc}
1260 yield {'topic': c, 'summary': doc}
1256
1261
1257 def othercommands(**map):
1262 def othercommands(**map):
1258 for c, doc in other:
1263 for c, doc in other:
1259 yield {'topic': c, 'summary': doc}
1264 yield {'topic': c, 'summary': doc}
1260
1265
1261 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
1266 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
1262 othercommands=othercommands, title='Index')
1267 othercommands=othercommands, title='Index')
1263
1268
1264 # Render an index of sub-topics.
1269 # Render an index of sub-topics.
1265 if topicname in helpmod.subtopics:
1270 if topicname in helpmod.subtopics:
1266 topics = []
1271 topics = []
1267 for entries, summary, _doc in helpmod.subtopics[topicname]:
1272 for entries, summary, _doc in helpmod.subtopics[topicname]:
1268 topics.append({
1273 topics.append({
1269 'topic': '%s.%s' % (topicname, entries[0]),
1274 'topic': '%s.%s' % (topicname, entries[0]),
1270 'basename': entries[0],
1275 'basename': entries[0],
1271 'summary': summary,
1276 'summary': summary,
1272 })
1277 })
1273
1278
1274 return tmpl('helptopics', topics=topics, title=topicname,
1279 return tmpl('helptopics', topics=topics, title=topicname,
1275 subindex=True)
1280 subindex=True)
1276
1281
1277 u = webutil.wsgiui()
1282 u = webutil.wsgiui()
1278 u.verbose = True
1283 u.verbose = True
1279
1284
1280 # Render a page from a sub-topic.
1285 # Render a page from a sub-topic.
1281 if '.' in topicname:
1286 if '.' in topicname:
1282 # TODO implement support for rendering sections, like
1287 # TODO implement support for rendering sections, like
1283 # `hg help` works.
1288 # `hg help` works.
1284 topic, subtopic = topicname.split('.', 1)
1289 topic, subtopic = topicname.split('.', 1)
1285 if topic not in helpmod.subtopics:
1290 if topic not in helpmod.subtopics:
1286 raise ErrorResponse(HTTP_NOT_FOUND)
1291 raise ErrorResponse(HTTP_NOT_FOUND)
1287 else:
1292 else:
1288 topic = topicname
1293 topic = topicname
1289 subtopic = None
1294 subtopic = None
1290
1295
1291 try:
1296 try:
1292 doc = helpmod.help_(u, topic, subtopic=subtopic)
1297 doc = helpmod.help_(u, topic, subtopic=subtopic)
1293 except error.UnknownCommand:
1298 except error.UnknownCommand:
1294 raise ErrorResponse(HTTP_NOT_FOUND)
1299 raise ErrorResponse(HTTP_NOT_FOUND)
1295 return tmpl('help', topic=topicname, doc=doc)
1300 return tmpl('help', topic=topicname, doc=doc)
1296
1301
1297 # tell hggettext to extract docstrings from these functions:
1302 # tell hggettext to extract docstrings from these functions:
1298 i18nfunctions = commands.values()
1303 i18nfunctions = commands.values()
@@ -1,331 +1,333 b''
1 default = 'summary'
1 default = 'summary'
2 mimetype = 'text/html; charset={encoding}'
2 mimetype = 'text/html; charset={encoding}'
3 header = header.tmpl
3 header = header.tmpl
4 footer = footer.tmpl
4 footer = footer.tmpl
5 search = search.tmpl
5 search = search.tmpl
6 changelog = changelog.tmpl
6 changelog = changelog.tmpl
7 summary = summary.tmpl
7 summary = summary.tmpl
8 error = error.tmpl
8 error = error.tmpl
9 notfound = notfound.tmpl
9 notfound = notfound.tmpl
10
10
11 help = help.tmpl
11 help = help.tmpl
12 helptopics = helptopics.tmpl
12 helptopics = helptopics.tmpl
13
13
14 helpentry = '
14 helpentry = '
15 <tr><td>
15 <tr><td>
16 <a href="{url|urlescape}help/{topic|escape}{sessionvars%urlparameter}">
16 <a href="{url|urlescape}help/{topic|escape}{sessionvars%urlparameter}">
17 {if(basename, '{basename|escape}', '{topic|escape}')}
17 {if(basename, '{basename|escape}', '{topic|escape}')}
18 </a>
18 </a>
19 </td><td>
19 </td><td>
20 {summary|escape}
20 {summary|escape}
21 </td></tr>'
21 </td></tr>'
22
22
23 naventry = '<a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
23 naventry = '<a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
24 navshortentry = '<a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
24 navshortentry = '<a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
25 navgraphentry = '<a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
25 navgraphentry = '<a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
26 filenaventry = '<a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
26 filenaventry = '<a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
27 filedifflink = '<a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
27 filedifflink = '<a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
28 filenodelink = '
28 filenodelink = '
29 <tr class="parity{parity}">
29 <tr class="parity{parity}">
30 <td><a class="list" href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
30 <td><a class="list" href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
31 <td></td>
31 <td></td>
32 <td class="link">
32 <td class="link">
33 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
33 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
34 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> |
34 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> |
35 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
35 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
36 <a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">comparison</a> |
36 <a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">comparison</a> |
37 <a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
37 <a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
38 </td>
38 </td>
39 </tr>'
39 </tr>'
40 filenolink = '
40 filenolink = '
41 <tr class="parity{parity}">
41 <tr class="parity{parity}">
42 <td><a class="list" href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
42 <td><a class="list" href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
43 <td></td>
43 <td></td>
44 <td class="link">
44 <td class="link">
45 file |
45 file |
46 annotate |
46 annotate |
47 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
47 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
48 <a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">comparison</a> |
48 <a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">comparison</a> |
49 <a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
49 <a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
50 </td>
50 </td>
51 </tr>'
51 </tr>'
52
52
53 nav = '{before%naventry} {after%naventry}'
53 nav = '{before%naventry} {after%naventry}'
54 navshort = '{before%navshortentry}{after%navshortentry}'
54 navshort = '{before%navshortentry}{after%navshortentry}'
55 navgraph = '{before%navgraphentry}{after%navgraphentry}'
55 navgraph = '{before%navgraphentry}{after%navgraphentry}'
56 filenav = '{before%filenaventry}{after%filenaventry}'
56 filenav = '{before%filenaventry}{after%filenaventry}'
57
57
58 fileellipses = '...'
58 fileellipses = '...'
59 changelogentry = changelogentry.tmpl
59 changelogentry = changelogentry.tmpl
60 searchentry = changelogentry.tmpl
60 searchentry = changelogentry.tmpl
61 changeset = changeset.tmpl
61 changeset = changeset.tmpl
62 manifest = manifest.tmpl
62 manifest = manifest.tmpl
63 direntry = '
63 direntry = '
64 <tr class="parity{parity}">
64 <tr class="parity{parity}">
65 <td style="font-family:monospace">drwxr-xr-x</td>
65 <td style="font-family:monospace">drwxr-xr-x</td>
66 <td style="font-family:monospace"></td>
66 <td style="font-family:monospace"></td>
67 <td style="font-family:monospace"></td>
67 <td style="font-family:monospace"></td>
68 <td>
68 <td>
69 <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>
69 <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>
70 <a href="{url|urlescape}file/{symrev}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">{emptydirs|escape}</a>
70 <a href="{url|urlescape}file/{symrev}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">{emptydirs|escape}</a>
71 </td>
71 </td>
72 <td class="link">
72 <td class="link">
73 <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">files</a>
73 <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">files</a>
74 </td>
74 </td>
75 </tr>'
75 </tr>'
76 fileentry = '
76 fileentry = '
77 <tr class="parity{parity}">
77 <tr class="parity{parity}">
78 <td style="font-family:monospace">{permissions|permissions}</td>
78 <td style="font-family:monospace">{permissions|permissions}</td>
79 <td style="font-family:monospace" align=right>{date|isodate}</td>
79 <td style="font-family:monospace" align=right>{date|isodate}</td>
80 <td style="font-family:monospace" align=right>{size}</td>
80 <td style="font-family:monospace" align=right>{size}</td>
81 <td class="list">
81 <td class="list">
82 <a class="list" href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>
82 <a class="list" href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>
83 </td>
83 </td>
84 <td class="link">
84 <td class="link">
85 <a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
85 <a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
86 <a href="{url|urlescape}log/{symrev}/{file|urlescape}{sessionvars%urlparameter}">revisions</a> |
86 <a href="{url|urlescape}log/{symrev}/{file|urlescape}{sessionvars%urlparameter}">revisions</a> |
87 <a href="{url|urlescape}annotate/{symrev}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
87 <a href="{url|urlescape}annotate/{symrev}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
88 </td>
88 </td>
89 </tr>'
89 </tr>'
90 filerevision = filerevision.tmpl
90 filerevision = filerevision.tmpl
91 fileannotate = fileannotate.tmpl
91 fileannotate = fileannotate.tmpl
92 filediff = filediff.tmpl
92 filediff = filediff.tmpl
93 filecomparison = filecomparison.tmpl
93 filecomparison = filecomparison.tmpl
94 filelog = filelog.tmpl
94 filelog = filelog.tmpl
95 fileline = '
95 fileline = '
96 <a href="#{lineid}"></a><span id="{lineid}">{strip(line|escape, '\r\n')}</span>'
96 <a href="#{lineid}"></a><span id="{lineid}">{strip(line|escape, '\r\n')}</span>'
97 annotateline = '
97 annotateline = '
98 <tr id="{lineid}" style="font-family:monospace" class="parity{parity}{ifeq(node, originalnode, ' thisrev')}">
98 <tr id="{lineid}" style="font-family:monospace" class="parity{parity}{ifeq(node, originalnode, ' thisrev')}">
99 <td class="linenr" style="text-align: right;">
99 <td class="linenr" style="text-align: right;">
100 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
100 {if(blockhead,
101 title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
101 '<a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
102 title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>',
103 '')}
102 </td>
104 </td>
103 <td><pre><a class="linenr" href="#{lineid}">{linenumber}</a></pre></td>
105 <td><pre><a class="linenr" href="#{lineid}">{linenumber}</a></pre></td>
104 <td><pre>{line|escape}</pre></td>
106 <td><pre>{line|escape}</pre></td>
105 </tr>'
107 </tr>'
106 difflineplus = '
108 difflineplus = '
107 <a href="#{lineid}"></a><span id="{lineid}" class="difflineplus">{strip(line|escape, '\r\n')}</span>'
109 <a href="#{lineid}"></a><span id="{lineid}" class="difflineplus">{strip(line|escape, '\r\n')}</span>'
108 difflineminus = '
110 difflineminus = '
109 <a href="#{lineid}"></a><span id="{lineid}" class="difflineminus">{strip(line|escape, '\r\n')}</span>'
111 <a href="#{lineid}"></a><span id="{lineid}" class="difflineminus">{strip(line|escape, '\r\n')}</span>'
110 difflineat = '
112 difflineat = '
111 <a href="#{lineid}"></a><span id="{lineid}" class="difflineat">{strip(line|escape, '\r\n')}</span>'
113 <a href="#{lineid}"></a><span id="{lineid}" class="difflineat">{strip(line|escape, '\r\n')}</span>'
112 diffline = '
114 diffline = '
113 <a href="#{lineid}"></a><span id="{lineid}">{strip(line|escape, '\r\n')}</span>'
115 <a href="#{lineid}"></a><span id="{lineid}">{strip(line|escape, '\r\n')}</span>'
114
116
115 comparisonblock ='
117 comparisonblock ='
116 <tbody class="block">
118 <tbody class="block">
117 {lines}
119 {lines}
118 </tbody>'
120 </tbody>'
119 comparisonline = '
121 comparisonline = '
120 <tr id="{lineid}" style="font-family:monospace">
122 <tr id="{lineid}" style="font-family:monospace">
121 <td class="{type}"><pre><a class="linenr" href="#{lineid}">{leftlinenumber}</a> {leftline|escape}</pre></td>
123 <td class="{type}"><pre><a class="linenr" href="#{lineid}">{leftlinenumber}</a> {leftline|escape}</pre></td>
122 <td class="{type}"><pre><a class="linenr" href="#{lineid}">{rightlinenumber}</a> {rightline|escape}</pre></td>
124 <td class="{type}"><pre><a class="linenr" href="#{lineid}">{rightlinenumber}</a> {rightline|escape}</pre></td>
123 </tr>'
125 </tr>'
124
126
125 changelogparent = '
127 changelogparent = '
126 <tr>
128 <tr>
127 <th class="parent">parent {rev}:</th>
129 <th class="parent">parent {rev}:</th>
128 <td class="parent">
130 <td class="parent">
129 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
131 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
130 </td>
132 </td>
131 </tr>'
133 </tr>'
132 changesetlink = '<a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
134 changesetlink = '<a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
133 changesetbranch = '<tr><td>branch</td><td>{name|escape}</td></tr>'
135 changesetbranch = '<tr><td>branch</td><td>{name|escape}</td></tr>'
134 changesetparent = '
136 changesetparent = '
135 <tr>
137 <tr>
136 <td>parent {rev}</td>
138 <td>parent {rev}</td>
137 <td style="font-family:monospace">
139 <td style="font-family:monospace">
138 {changesetlink}
140 {changesetlink}
139 </td>
141 </td>
140 </tr>'
142 </tr>'
141 changesetparentdiff = '
143 changesetparentdiff = '
142 <tr>
144 <tr>
143 <td>parent {rev}</td>
145 <td>parent {rev}</td>
144 <td style="font-family:monospace">
146 <td style="font-family:monospace">
145 {changesetlink} {ifeq(node, basenode, '(current diff)', '({difffrom})')}
147 {changesetlink} {ifeq(node, basenode, '(current diff)', '({difffrom})')}
146 </td>
148 </td>
147 </tr>'
149 </tr>'
148 difffrom = '<a href="{url|urlescape}rev/{node|short}:{originalnode|short}{sessionvars%urlparameter}">diff</a>'
150 difffrom = '<a href="{url|urlescape}rev/{node|short}:{originalnode|short}{sessionvars%urlparameter}">diff</a>'
149 filerevbranch = '<tr><td>branch</td><td>{name|escape}</td></tr>'
151 filerevbranch = '<tr><td>branch</td><td>{name|escape}</td></tr>'
150 filerevparent = '
152 filerevparent = '
151 <tr>
153 <tr>
152 <td>parent {rev}</td>
154 <td>parent {rev}</td>
153 <td style="font-family:monospace">
155 <td style="font-family:monospace">
154 <a class="list" href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
156 <a class="list" href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
155 {rename%filerename}{node|short}
157 {rename%filerename}{node|short}
156 </a>
158 </a>
157 </td>
159 </td>
158 </tr>'
160 </tr>'
159 filerename = '{file|escape}@'
161 filerename = '{file|escape}@'
160 filelogrename = '| <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">base</a>'
162 filelogrename = '| <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">base</a>'
161 fileannotateparent = '
163 fileannotateparent = '
162 <tr>
164 <tr>
163 <td>parent {rev}</td>
165 <td>parent {rev}</td>
164 <td style="font-family:monospace">
166 <td style="font-family:monospace">
165 <a class="list" href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
167 <a class="list" href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
166 {rename%filerename}{node|short}
168 {rename%filerename}{node|short}
167 </a>
169 </a>
168 </td>
170 </td>
169 </tr>'
171 </tr>'
170 changelogchild = '
172 changelogchild = '
171 <tr>
173 <tr>
172 <th class="child">child {rev}:</th>
174 <th class="child">child {rev}:</th>
173 <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
175 <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
174 </tr>'
176 </tr>'
175 changesetchild = '
177 changesetchild = '
176 <tr>
178 <tr>
177 <td>child {rev}</td>
179 <td>child {rev}</td>
178 <td style="font-family:monospace">
180 <td style="font-family:monospace">
179 <a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
181 <a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
180 </td>
182 </td>
181 </tr>'
183 </tr>'
182 filerevchild = '
184 filerevchild = '
183 <tr>
185 <tr>
184 <td>child {rev}</td>
186 <td>child {rev}</td>
185 <td style="font-family:monospace">
187 <td style="font-family:monospace">
186 <a class="list" href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
188 <a class="list" href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
187 </tr>'
189 </tr>'
188 fileannotatechild = '
190 fileannotatechild = '
189 <tr>
191 <tr>
190 <td>child {rev}</td>
192 <td>child {rev}</td>
191 <td style="font-family:monospace">
193 <td style="font-family:monospace">
192 <a class="list" href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
194 <a class="list" href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
193 </tr>'
195 </tr>'
194 tags = tags.tmpl
196 tags = tags.tmpl
195 tagentry = '
197 tagentry = '
196 <tr class="parity{parity}">
198 <tr class="parity{parity}">
197 <td class="age"><i class="age">{date|rfc822date}</i></td>
199 <td class="age"><i class="age">{date|rfc822date}</i></td>
198 <td><a class="list" href="{url|urlescape}rev/{tag|revescape}{sessionvars%urlparameter}"><b>{tag|escape}</b></a></td>
200 <td><a class="list" href="{url|urlescape}rev/{tag|revescape}{sessionvars%urlparameter}"><b>{tag|escape}</b></a></td>
199 <td class="link">
201 <td class="link">
200 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
202 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
201 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
203 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
202 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
204 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
203 </td>
205 </td>
204 </tr>'
206 </tr>'
205 bookmarks = bookmarks.tmpl
207 bookmarks = bookmarks.tmpl
206 bookmarkentry = '
208 bookmarkentry = '
207 <tr class="parity{parity}">
209 <tr class="parity{parity}">
208 <td class="age"><i class="age">{date|rfc822date}</i></td>
210 <td class="age"><i class="age">{date|rfc822date}</i></td>
209 <td><a class="list" href="{url|urlescape}rev/{bookmark|revescape}{sessionvars%urlparameter}"><b>{bookmark|escape}</b></a></td>
211 <td><a class="list" href="{url|urlescape}rev/{bookmark|revescape}{sessionvars%urlparameter}"><b>{bookmark|escape}</b></a></td>
210 <td class="link">
212 <td class="link">
211 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
213 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
212 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
214 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
213 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
215 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
214 </td>
216 </td>
215 </tr>'
217 </tr>'
216 branches = branches.tmpl
218 branches = branches.tmpl
217 branchentry = '
219 branchentry = '
218 <tr class="parity{parity}">
220 <tr class="parity{parity}">
219 <td class="age"><i class="age">{date|rfc822date}</i></td>
221 <td class="age"><i class="age">{date|rfc822date}</i></td>
220 <td class="{status}"><a class="list" href="{url|urlescape}shortlog/{branch|revescape}{sessionvars%urlparameter}"><b>{branch|escape}</b></a></td>
222 <td class="{status}"><a class="list" href="{url|urlescape}shortlog/{branch|revescape}{sessionvars%urlparameter}"><b>{branch|escape}</b></a></td>
221 <td class="link">
223 <td class="link">
222 <a href="{url|urlescape}changeset/{node|short}{sessionvars%urlparameter}">changeset</a> |
224 <a href="{url|urlescape}changeset/{node|short}{sessionvars%urlparameter}">changeset</a> |
223 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
225 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
224 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
226 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
225 </td>
227 </td>
226 </tr>'
228 </tr>'
227 diffblock = '<div class="diffblock"><pre class="sourcelines">{lines}</pre></div>'
229 diffblock = '<div class="diffblock"><pre class="sourcelines">{lines}</pre></div>'
228 filediffparent = '
230 filediffparent = '
229 <tr>
231 <tr>
230 <td>parent {rev}</td>
232 <td>parent {rev}</td>
231 <td style="font-family:monospace">
233 <td style="font-family:monospace">
232 <a class="list" href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
234 <a class="list" href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
233 {node|short}
235 {node|short}
234 </a>
236 </a>
235 </td>
237 </td>
236 </tr>'
238 </tr>'
237 filecompparent = '
239 filecompparent = '
238 <tr>
240 <tr>
239 <td>parent {rev}</td>
241 <td>parent {rev}</td>
240 <td style="font-family:monospace">
242 <td style="font-family:monospace">
241 <a class="list" href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
243 <a class="list" href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
242 {node|short}
244 {node|short}
243 </a>
245 </a>
244 </td>
246 </td>
245 </tr>'
247 </tr>'
246 filelogparent = '
248 filelogparent = '
247 <tr>
249 <tr>
248 <td align="right">parent {rev}:&nbsp;</td>
250 <td align="right">parent {rev}:&nbsp;</td>
249 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
251 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
250 </tr>'
252 </tr>'
251 filediffchild = '
253 filediffchild = '
252 <tr>
254 <tr>
253 <td>child {rev}</td>
255 <td>child {rev}</td>
254 <td style="font-family:monospace">
256 <td style="font-family:monospace">
255 <a class="list" href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
257 <a class="list" href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
256 </td>
258 </td>
257 </tr>'
259 </tr>'
258 filecompchild = '
260 filecompchild = '
259 <tr>
261 <tr>
260 <td>child {rev}</td>
262 <td>child {rev}</td>
261 <td style="font-family:monospace">
263 <td style="font-family:monospace">
262 <a class="list" href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
264 <a class="list" href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
263 </td>
265 </td>
264 </tr>'
266 </tr>'
265 filelogchild = '
267 filelogchild = '
266 <tr>
268 <tr>
267 <td align="right">child {rev}:&nbsp;</td>
269 <td align="right">child {rev}:&nbsp;</td>
268 <td><a href="{url|urlescape}file{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
270 <td><a href="{url|urlescape}file{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
269 </tr>'
271 </tr>'
270 shortlog = shortlog.tmpl
272 shortlog = shortlog.tmpl
271 graph = graph.tmpl
273 graph = graph.tmpl
272 tagtag = '<span class="tagtag" title="{name|escape}">{name|escape}</span> '
274 tagtag = '<span class="tagtag" title="{name|escape}">{name|escape}</span> '
273 branchtag = '<span class="branchtag" title="{name|escape}">{name|escape}</span> '
275 branchtag = '<span class="branchtag" title="{name|escape}">{name|escape}</span> '
274 inbranchtag = '<span class="inbranchtag" title="{name|escape}">{name|escape}</span> '
276 inbranchtag = '<span class="inbranchtag" title="{name|escape}">{name|escape}</span> '
275 bookmarktag = '<span class="bookmarktag" title="{name|escape}">{name|escape}</span> '
277 bookmarktag = '<span class="bookmarktag" title="{name|escape}">{name|escape}</span> '
276 shortlogentry = '
278 shortlogentry = '
277 <tr class="parity{parity}">
279 <tr class="parity{parity}">
278 <td class="age"><i class="age">{date|rfc822date}</i></td>
280 <td class="age"><i class="age">{date|rfc822date}</i></td>
279 <td><i>{author|person}</i></td>
281 <td><i>{author|person}</i></td>
280 <td>
282 <td>
281 <a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
283 <a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
282 <b>{desc|strip|firstline|escape|nonempty}</b>
284 <b>{desc|strip|firstline|escape|nonempty}</b>
283 <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}{bookmarks%bookmarktag}</span>
285 <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}{bookmarks%bookmarktag}</span>
284 </a>
286 </a>
285 </td>
287 </td>
286 <td class="link" nowrap>
288 <td class="link" nowrap>
287 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
289 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
288 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
290 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
289 </td>
291 </td>
290 </tr>'
292 </tr>'
291 filelogentry = '
293 filelogentry = '
292 <tr class="parity{parity}">
294 <tr class="parity{parity}">
293 <td class="age"><i class="age">{date|rfc822date}</i></td>
295 <td class="age"><i class="age">{date|rfc822date}</i></td>
294 <td><i>{author|person}</i></td>
296 <td><i>{author|person}</i></td>
295 <td>
297 <td>
296 <a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
298 <a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
297 <b>{desc|strip|firstline|escape|nonempty}</b>
299 <b>{desc|strip|firstline|escape|nonempty}</b>
298 <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}{bookmarks%bookmarktag}</span>
300 <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}{bookmarks%bookmarktag}</span>
299 </a>
301 </a>
300 </td>
302 </td>
301 <td class="link">
303 <td class="link">
302 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
304 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
303 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
305 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
304 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
306 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
305 {rename%filelogrename}
307 {rename%filelogrename}
306 </td>
308 </td>
307 </tr>'
309 </tr>'
308 archiveentry = ' | <a href="{url|urlescape}archive/{symrev}{extension}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a> '
310 archiveentry = ' | <a href="{url|urlescape}archive/{symrev}{extension}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a> '
309 indexentry = '
311 indexentry = '
310 <tr class="parity{parity}">
312 <tr class="parity{parity}">
311 <td>
313 <td>
312 <a class="list" href="{url|urlescape}{sessionvars%urlparameter}">
314 <a class="list" href="{url|urlescape}{sessionvars%urlparameter}">
313 <b>{name|escape}</b>
315 <b>{name|escape}</b>
314 </a>
316 </a>
315 </td>
317 </td>
316 <td>{description}</td>
318 <td>{description}</td>
317 <td>{contact|obfuscate}</td>
319 <td>{contact|obfuscate}</td>
318 <td class="age">{lastchange|rfc822date}</td>
320 <td class="age">{lastchange|rfc822date}</td>
319 <td class="indexlinks">{archives%indexarchiveentry}</td>
321 <td class="indexlinks">{archives%indexarchiveentry}</td>
320 <td>{if(isdirectory, '',
322 <td>{if(isdirectory, '',
321 '<div class="rss_logo">
323 '<div class="rss_logo">
322 <a href="{url|urlescape}rss-log">RSS</a> <a href="{url|urlescape}atom-log">Atom</a>
324 <a href="{url|urlescape}rss-log">RSS</a> <a href="{url|urlescape}atom-log">Atom</a>
323 </div>'
325 </div>'
324 )}
326 )}
325 </td>
327 </td>
326 </tr>\n'
328 </tr>\n'
327 indexarchiveentry = ' <a href="{url|urlescape}archive/{node|short}{extension}">{type|escape}</a> '
329 indexarchiveentry = ' <a href="{url|urlescape}archive/{node|short}{extension}">{type|escape}</a> '
328 index = index.tmpl
330 index = index.tmpl
329 urlparameter = '{separator}{name}={value|urlescape}'
331 urlparameter = '{separator}{name}={value|urlescape}'
330 hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
332 hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
331 breadcrumb = '&gt; <a href="{url|urlescape}">{name|escape}</a> '
333 breadcrumb = '&gt; <a href="{url|urlescape}">{name|escape}</a> '
@@ -1,286 +1,288 b''
1 default = 'summary'
1 default = 'summary'
2 mimetype = 'text/html; charset={encoding}'
2 mimetype = 'text/html; charset={encoding}'
3 header = header.tmpl
3 header = header.tmpl
4 footer = footer.tmpl
4 footer = footer.tmpl
5 search = search.tmpl
5 search = search.tmpl
6 changelog = changelog.tmpl
6 changelog = changelog.tmpl
7 summary = summary.tmpl
7 summary = summary.tmpl
8 error = error.tmpl
8 error = error.tmpl
9 notfound = notfound.tmpl
9 notfound = notfound.tmpl
10
10
11 help = help.tmpl
11 help = help.tmpl
12 helptopics = helptopics.tmpl
12 helptopics = helptopics.tmpl
13
13
14 helpentry = '
14 helpentry = '
15 <tr><td>
15 <tr><td>
16 <a href="{url|urlescape}help/{topic|escape}{sessionvars%urlparameter}">
16 <a href="{url|urlescape}help/{topic|escape}{sessionvars%urlparameter}">
17 {if(basename, '{basename|escape}', '{topic|escape}')}
17 {if(basename, '{basename|escape}', '{topic|escape}')}
18 </a>
18 </a>
19 </td><td>
19 </td><td>
20 {summary|escape}
20 {summary|escape}
21 </td></tr>'
21 </td></tr>'
22
22
23 naventry = '<a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
23 naventry = '<a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
24 navshortentry = '<a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
24 navshortentry = '<a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
25 navgraphentry = '<a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
25 navgraphentry = '<a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
26 filenaventry = '<a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
26 filenaventry = '<a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
27 filedifflink = '<a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
27 filedifflink = '<a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
28 filenodelink = '
28 filenodelink = '
29 <tr class="parity{parity}">
29 <tr class="parity{parity}">
30 <td><a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
30 <td><a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
31 <td></td>
31 <td></td>
32 <td>
32 <td>
33 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
33 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
34 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> |
34 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> |
35 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
35 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
36 <a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">comparison</a> |
36 <a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">comparison</a> |
37 <a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
37 <a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
38 </td>
38 </td>
39 </tr>'
39 </tr>'
40 filenolink = '
40 filenolink = '
41 <tr class="parity{parity}">
41 <tr class="parity{parity}">
42 <td><a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
42 <td><a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a></td>
43 <td></td>
43 <td></td>
44 <td>
44 <td>
45 file |
45 file |
46 annotate |
46 annotate |
47 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
47 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
48 <a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">comparison</a> |
48 <a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">comparison</a> |
49 <a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
49 <a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a>
50 </td>
50 </td>
51 </tr>'
51 </tr>'
52
52
53 nav = '{before%naventry} {after%naventry}'
53 nav = '{before%naventry} {after%naventry}'
54 navshort = '{before%navshortentry}{after%navshortentry}'
54 navshort = '{before%navshortentry}{after%navshortentry}'
55 navgraph = '{before%navgraphentry}{after%navgraphentry}'
55 navgraph = '{before%navgraphentry}{after%navgraphentry}'
56 filenav = '{before%filenaventry}{after%filenaventry}'
56 filenav = '{before%filenaventry}{after%filenaventry}'
57
57
58 fileellipses = '...'
58 fileellipses = '...'
59 changelogentry = changelogentry.tmpl
59 changelogentry = changelogentry.tmpl
60 searchentry = changelogentry.tmpl
60 searchentry = changelogentry.tmpl
61 changeset = changeset.tmpl
61 changeset = changeset.tmpl
62 manifest = manifest.tmpl
62 manifest = manifest.tmpl
63 direntry = '
63 direntry = '
64 <tr class="parity{parity}">
64 <tr class="parity{parity}">
65 <td>drwxr-xr-x</td>
65 <td>drwxr-xr-x</td>
66 <td></td>
66 <td></td>
67 <td></td>
67 <td></td>
68 <td>
68 <td>
69 <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>
69 <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>
70 <a href="{url|urlescape}file/{symrev}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">{emptydirs|escape}</a>
70 <a href="{url|urlescape}file/{symrev}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">{emptydirs|escape}</a>
71 </td>
71 </td>
72 <td><a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">files</a></td>
72 <td><a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">files</a></td>
73 </tr>'
73 </tr>'
74 fileentry = '
74 fileentry = '
75 <tr class="parity{parity}">
75 <tr class="parity{parity}">
76 <td>{permissions|permissions}</td>
76 <td>{permissions|permissions}</td>
77 <td>{date|isodate}</td>
77 <td>{date|isodate}</td>
78 <td>{size}</td>
78 <td>{size}</td>
79 <td><a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">{basename|escape}</a></td>
79 <td><a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">{basename|escape}</a></td>
80 <td>
80 <td>
81 <a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
81 <a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
82 <a href="{url|urlescape}log/{symrev}/{file|urlescape}{sessionvars%urlparameter}">revisions</a> |
82 <a href="{url|urlescape}log/{symrev}/{file|urlescape}{sessionvars%urlparameter}">revisions</a> |
83 <a href="{url|urlescape}annotate/{symrev}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
83 <a href="{url|urlescape}annotate/{symrev}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
84 </td>
84 </td>
85 </tr>'
85 </tr>'
86 filerevision = filerevision.tmpl
86 filerevision = filerevision.tmpl
87 fileannotate = fileannotate.tmpl
87 fileannotate = fileannotate.tmpl
88 filediff = filediff.tmpl
88 filediff = filediff.tmpl
89 filecomparison = filecomparison.tmpl
89 filecomparison = filecomparison.tmpl
90 filelog = filelog.tmpl
90 filelog = filelog.tmpl
91 fileline = '
91 fileline = '
92 <a href="#{lineid}"></a><span id="{lineid}">{strip(line|escape, '\r\n')}</span>'
92 <a href="#{lineid}"></a><span id="{lineid}">{strip(line|escape, '\r\n')}</span>'
93 annotateline = '
93 annotateline = '
94 <tr id="{lineid}" class="parity{parity}{ifeq(node, originalnode, ' thisrev')}">
94 <tr id="{lineid}" class="parity{parity}{ifeq(node, originalnode, ' thisrev')}">
95 <td class="linenr">
95 <td class="linenr">
96 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
96 {if(blockhead,
97 title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
97 '<a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
98 title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>',
99 '')}
98 </td>
100 </td>
99 <td class="lineno">
101 <td class="lineno">
100 <a href="#{lineid}">{linenumber}</a>
102 <a href="#{lineid}">{linenumber}</a>
101 </td>
103 </td>
102 <td class="source">{line|escape}</td>
104 <td class="source">{line|escape}</td>
103 </tr>'
105 </tr>'
104 difflineplus = '
106 difflineplus = '
105 <a href="#{lineid}"></a><span id="{lineid}" class="difflineplus">{strip(line|escape, '\r\n')}</span>'
107 <a href="#{lineid}"></a><span id="{lineid}" class="difflineplus">{strip(line|escape, '\r\n')}</span>'
106 difflineminus = '
108 difflineminus = '
107 <a href="#{lineid}"></a><span id="{lineid}" class="difflineminus">{strip(line|escape, '\r\n')}</span>'
109 <a href="#{lineid}"></a><span id="{lineid}" class="difflineminus">{strip(line|escape, '\r\n')}</span>'
108 difflineat = '
110 difflineat = '
109 <a href="#{lineid}"></a><span id="{lineid}" class="difflineat">{strip(line|escape, '\r\n')}</span>'
111 <a href="#{lineid}"></a><span id="{lineid}" class="difflineat">{strip(line|escape, '\r\n')}</span>'
110 diffline = '
112 diffline = '
111 <a href="#{lineid}"></a><span id="{lineid}">{strip(line|escape, '\r\n')}</span>'
113 <a href="#{lineid}"></a><span id="{lineid}">{strip(line|escape, '\r\n')}</span>'
112
114
113 comparisonblock ='
115 comparisonblock ='
114 <tbody class="block">
116 <tbody class="block">
115 {lines}
117 {lines}
116 </tbody>'
118 </tbody>'
117 comparisonline = '
119 comparisonline = '
118 <tr id="{lineid}">
120 <tr id="{lineid}">
119 <td class="source {type}"><a class="linenr" href="#{lineid}">{leftlinenumber}</a> {leftline|escape}</td>
121 <td class="source {type}"><a class="linenr" href="#{lineid}">{leftlinenumber}</a> {leftline|escape}</td>
120 <td class="source {type}"><a class="linenr" href="#{lineid}">{rightlinenumber}</a> {rightline|escape}</td>
122 <td class="source {type}"><a class="linenr" href="#{lineid}">{rightlinenumber}</a> {rightline|escape}</td>
121 </tr>'
123 </tr>'
122
124
123 changesetlink = '<a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
125 changesetlink = '<a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
124 changelogparent = '
126 changelogparent = '
125 <tr>
127 <tr>
126 <th class="parent">parent {rev}:</th>
128 <th class="parent">parent {rev}:</th>
127 <td class="parent">
129 <td class="parent">
128 {changesetlink}
130 {changesetlink}
129 </td>
131 </td>
130 </tr>'
132 </tr>'
131 changesetbranch = '<dt>branch</dt><dd>{name|escape}</dd>'
133 changesetbranch = '<dt>branch</dt><dd>{name|escape}</dd>'
132 changesetparent = '
134 changesetparent = '
133 <dt>parent {rev}</dt>
135 <dt>parent {rev}</dt>
134 <dd>{changesetlink}</dd>'
136 <dd>{changesetlink}</dd>'
135 changesetparentdiff = '
137 changesetparentdiff = '
136 <dt>parent {rev}</dt>
138 <dt>parent {rev}</dt>
137 <dd>{changesetlink} {ifeq(node, basenode, '(current diff)', '({difffrom})')}</dd>'
139 <dd>{changesetlink} {ifeq(node, basenode, '(current diff)', '({difffrom})')}</dd>'
138 difffrom = '<a href="{url|urlescape}rev/{node|short}:{originalnode|short}{sessionvars%urlparameter}">diff</a>'
140 difffrom = '<a href="{url|urlescape}rev/{node|short}:{originalnode|short}{sessionvars%urlparameter}">diff</a>'
139 filerevbranch = '<dt>branch</dt><dd>{name|escape}</dd>'
141 filerevbranch = '<dt>branch</dt><dd>{name|escape}</dd>'
140 filerevparent = '
142 filerevparent = '
141 <dt>parent {rev}</dt>
143 <dt>parent {rev}</dt>
142 <dd>
144 <dd>
143 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
145 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
144 {rename%filerename}{node|short}
146 {rename%filerename}{node|short}
145 </a>
147 </a>
146 </dd>'
148 </dd>'
147 filerename = '{file|escape}@'
149 filerename = '{file|escape}@'
148 filelogrename = '| <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">base</a>'
150 filelogrename = '| <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">base</a>'
149 fileannotateparent = '
151 fileannotateparent = '
150 <dt>parent {rev}</dt>
152 <dt>parent {rev}</dt>
151 <dd>
153 <dd>
152 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
154 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
153 {rename%filerename}{node|short}
155 {rename%filerename}{node|short}
154 </a>
156 </a>
155 </dd>'
157 </dd>'
156 changelogchild = '
158 changelogchild = '
157 <dt>child {rev}:</dt>
159 <dt>child {rev}:</dt>
158 <dd><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>'
160 <dd><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>'
159 changesetchild = '
161 changesetchild = '
160 <dt>child {rev}</dt>
162 <dt>child {rev}</dt>
161 <dd><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>'
163 <dd><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></dd>'
162 filerevchild = '
164 filerevchild = '
163 <dt>child {rev}</dt>
165 <dt>child {rev}</dt>
164 <dd>
166 <dd>
165 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
167 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
166 </dd>'
168 </dd>'
167 fileannotatechild = '
169 fileannotatechild = '
168 <dt>child {rev}</dt>
170 <dt>child {rev}</dt>
169 <dd>
171 <dd>
170 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
172 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a>
171 </dd>'
173 </dd>'
172 tags = tags.tmpl
174 tags = tags.tmpl
173 tagentry = '
175 tagentry = '
174 <tr class="parity{parity}">
176 <tr class="parity{parity}">
175 <td class="nowrap age">{date|rfc822date}</td>
177 <td class="nowrap age">{date|rfc822date}</td>
176 <td><a href="{url|urlescape}rev/{tag|revescape}{sessionvars%urlparameter}">{tag|escape}</a></td>
178 <td><a href="{url|urlescape}rev/{tag|revescape}{sessionvars%urlparameter}">{tag|escape}</a></td>
177 <td class="nowrap">
179 <td class="nowrap">
178 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
180 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
179 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
181 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
180 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
182 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
181 </td>
183 </td>
182 </tr>'
184 </tr>'
183 bookmarks = bookmarks.tmpl
185 bookmarks = bookmarks.tmpl
184 bookmarkentry = '
186 bookmarkentry = '
185 <tr class="parity{parity}">
187 <tr class="parity{parity}">
186 <td class="nowrap age">{date|rfc822date}</td>
188 <td class="nowrap age">{date|rfc822date}</td>
187 <td><a href="{url|urlescape}rev/{bookmark|revescape}{sessionvars%urlparameter}">{bookmark|escape}</a></td>
189 <td><a href="{url|urlescape}rev/{bookmark|revescape}{sessionvars%urlparameter}">{bookmark|escape}</a></td>
188 <td class="nowrap">
190 <td class="nowrap">
189 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
191 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
190 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
192 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
191 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
193 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
192 </td>
194 </td>
193 </tr>'
195 </tr>'
194 branches = branches.tmpl
196 branches = branches.tmpl
195 branchentry = '
197 branchentry = '
196 <tr class="parity{parity}">
198 <tr class="parity{parity}">
197 <td class="nowrap age">{date|rfc822date}</td>
199 <td class="nowrap age">{date|rfc822date}</td>
198 <td class="{status}"><a href="{url|urlescape}shortlog/{branch|revescape}{sessionvars%urlparameter}">{branch|escape}</a></td>
200 <td class="{status}"><a href="{url|urlescape}shortlog/{branch|revescape}{sessionvars%urlparameter}">{branch|escape}</a></td>
199 <td class="nowrap">
201 <td class="nowrap">
200 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
202 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
201 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
203 <a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">changelog</a> |
202 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
204 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
203 </td>
205 </td>
204 </tr>'
206 </tr>'
205 diffblock = '<div class="diffblock"><pre class="sourcelines">{lines}</pre></div>'
207 diffblock = '<div class="diffblock"><pre class="sourcelines">{lines}</pre></div>'
206 filediffparent = '
208 filediffparent = '
207 <dt>parent {rev}</dt>
209 <dt>parent {rev}</dt>
208 <dd><a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
210 <dd><a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
209 filecompparent = '
211 filecompparent = '
210 <dt>parent {rev}</dt>
212 <dt>parent {rev}</dt>
211 <dd><a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
213 <dd><a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
212 filelogparent = '
214 filelogparent = '
213 <tr>
215 <tr>
214 <td align="right">parent {rev}:&nbsp;</td>
216 <td align="right">parent {rev}:&nbsp;</td>
215 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
217 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
216 </tr>'
218 </tr>'
217 filediffchild = '
219 filediffchild = '
218 <dt>child {rev}</dt>
220 <dt>child {rev}</dt>
219 <dd><a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
221 <dd><a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
220 filecompchild = '
222 filecompchild = '
221 <dt>child {rev}</dt>
223 <dt>child {rev}</dt>
222 <dd><a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
224 <dd><a href="{url|urlescape}comparison/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
223 filelogchild = '
225 filelogchild = '
224 <tr>
226 <tr>
225 <td align="right">child {rev}:&nbsp;</td>
227 <td align="right">child {rev}:&nbsp;</td>
226 <td><a href="{url|urlescape}file{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
228 <td><a href="{url|urlescape}file{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
227 </tr>'
229 </tr>'
228 shortlog = shortlog.tmpl
230 shortlog = shortlog.tmpl
229 tagtag = '<span class="tagtag" title="{name|escape}">{name|escape}</span> '
231 tagtag = '<span class="tagtag" title="{name|escape}">{name|escape}</span> '
230 branchtag = '<span class="branchtag" title="{name|escape}">{name|escape}</span> '
232 branchtag = '<span class="branchtag" title="{name|escape}">{name|escape}</span> '
231 inbranchtag = '<span class="inbranchtag" title="{name|escape}">{name|escape}</span> '
233 inbranchtag = '<span class="inbranchtag" title="{name|escape}">{name|escape}</span> '
232 bookmarktag = '<span class="bookmarktag" title="{name|escape}">{name|escape}</span> '
234 bookmarktag = '<span class="bookmarktag" title="{name|escape}">{name|escape}</span> '
233 shortlogentry = '
235 shortlogentry = '
234 <tr class="parity{parity}">
236 <tr class="parity{parity}">
235 <td class="nowrap age">{date|rfc822date}</td>
237 <td class="nowrap age">{date|rfc822date}</td>
236 <td>{author|person}</td>
238 <td>{author|person}</td>
237 <td>
239 <td>
238 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
240 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
239 {desc|strip|firstline|escape|nonempty}
241 {desc|strip|firstline|escape|nonempty}
240 <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}{bookmarks%bookmarktag}</span>
242 <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}{bookmarks%bookmarktag}</span>
241 </a>
243 </a>
242 </td>
244 </td>
243 <td class="nowrap">
245 <td class="nowrap">
244 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
246 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
245 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
247 <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
246 </td>
248 </td>
247 </tr>'
249 </tr>'
248 filelogentry = '
250 filelogentry = '
249 <tr class="parity{parity}">
251 <tr class="parity{parity}">
250 <td class="nowrap age">{date|rfc822date}</td>
252 <td class="nowrap age">{date|rfc822date}</td>
251 <td>{author|person}</td>
253 <td>{author|person}</td>
252 <td>
254 <td>
253 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
255 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
254 {desc|strip|firstline|escape|nonempty}
256 {desc|strip|firstline|escape|nonempty}
255 <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}{bookmarks%bookmarktag}</span>
257 <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}{bookmarks%bookmarktag}</span>
256 </a>
258 </a>
257 </td>
259 </td>
258 <td class="nowrap">
260 <td class="nowrap">
259 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
261 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
260 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
262 <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
261 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
263 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
262 {rename%filelogrename}
264 {rename%filelogrename}
263 </td>
265 </td>
264 </tr>'
266 </tr>'
265 archiveentry = '<li><a href="{url|urlescape}archive/{symrev}{extension}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a></li>'
267 archiveentry = '<li><a href="{url|urlescape}archive/{symrev}{extension}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a></li>'
266 indexentry = '
268 indexentry = '
267 <tr class="parity{parity}">
269 <tr class="parity{parity}">
268 <td><a href="{url|urlescape}{sessionvars%urlparameter}">{name|escape}</a></td>
270 <td><a href="{url|urlescape}{sessionvars%urlparameter}">{name|escape}</a></td>
269 <td>{description}</td>
271 <td>{description}</td>
270 <td>{contact|obfuscate}</td>
272 <td>{contact|obfuscate}</td>
271 <td class="age">{lastchange|rfc822date}</td>
273 <td class="age">{lastchange|rfc822date}</td>
272 <td class="indexlinks">{archives%indexarchiveentry}</td>
274 <td class="indexlinks">{archives%indexarchiveentry}</td>
273 <td>
275 <td>
274 {if(isdirectory, '',
276 {if(isdirectory, '',
275 '<div class="rss_logo">
277 '<div class="rss_logo">
276 <a href="{url|urlescape}rss-log">RSS</a> <a href="{url|urlescape}atom-log">Atom</a>
278 <a href="{url|urlescape}rss-log">RSS</a> <a href="{url|urlescape}atom-log">Atom</a>
277 </div>'
279 </div>'
278 )}
280 )}
279 </td>
281 </td>
280 </tr>\n'
282 </tr>\n'
281 indexarchiveentry = '<a href="{url|urlescape}archive/{node|short}{extension}">{type|escape}</a> '
283 indexarchiveentry = '<a href="{url|urlescape}archive/{node|short}{extension}">{type|escape}</a> '
282 index = index.tmpl
284 index = index.tmpl
283 urlparameter = '{separator}{name}={value|urlescape}'
285 urlparameter = '{separator}{name}={value|urlescape}'
284 hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
286 hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
285 graph = graph.tmpl
287 graph = graph.tmpl
286 breadcrumb = '&gt; <a href="{url|urlescape}">{name|escape}</a> '
288 breadcrumb = '&gt; <a href="{url|urlescape}">{name|escape}</a> '
@@ -1,258 +1,260 b''
1 default = 'shortlog'
1 default = 'shortlog'
2
2
3 mimetype = 'text/html; charset={encoding}'
3 mimetype = 'text/html; charset={encoding}'
4 header = header.tmpl
4 header = header.tmpl
5 footer = footer.tmpl
5 footer = footer.tmpl
6 search = search.tmpl
6 search = search.tmpl
7
7
8 changelog = shortlog.tmpl
8 changelog = shortlog.tmpl
9 shortlog = shortlog.tmpl
9 shortlog = shortlog.tmpl
10 shortlogentry = shortlogentry.tmpl
10 shortlogentry = shortlogentry.tmpl
11 graph = graph.tmpl
11 graph = graph.tmpl
12 help = help.tmpl
12 help = help.tmpl
13 helptopics = helptopics.tmpl
13 helptopics = helptopics.tmpl
14
14
15 helpentry = '
15 helpentry = '
16 <tr><td>
16 <tr><td>
17 <a href="{url|urlescape}help/{topic|escape}{sessionvars%urlparameter}">
17 <a href="{url|urlescape}help/{topic|escape}{sessionvars%urlparameter}">
18 {if(basename, '{basename|escape}', '{topic|escape}')}
18 {if(basename, '{basename|escape}', '{topic|escape}')}
19 </a>
19 </a>
20 </td><td>
20 </td><td>
21 {summary|escape}
21 {summary|escape}
22 </td></tr>'
22 </td></tr>'
23
23
24 naventry = '<a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
24 naventry = '<a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
25 navshortentry = '<a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
25 navshortentry = '<a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
26 navgraphentry = '<a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
26 navgraphentry = '<a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
27 filenaventry = '<a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
27 filenaventry = '<a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
28 filedifflink = '<a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
28 filedifflink = '<a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
29 filenodelink = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
29 filenodelink = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
30 filenolink = '{file|escape} '
30 filenolink = '{file|escape} '
31 fileellipses = '...'
31 fileellipses = '...'
32 diffstatlink = diffstat.tmpl
32 diffstatlink = diffstat.tmpl
33 diffstatnolink = diffstat.tmpl
33 diffstatnolink = diffstat.tmpl
34 changelogentry = shortlogentry.tmpl
34 changelogentry = shortlogentry.tmpl
35 searchentry = shortlogentry.tmpl
35 searchentry = shortlogentry.tmpl
36 changeset = changeset.tmpl
36 changeset = changeset.tmpl
37 manifest = manifest.tmpl
37 manifest = manifest.tmpl
38
38
39 nav = '{before%naventry} {after%naventry}'
39 nav = '{before%naventry} {after%naventry}'
40 navshort = '{before%navshortentry}{after%navshortentry}'
40 navshort = '{before%navshortentry}{after%navshortentry}'
41 navgraph = '{before%navgraphentry}{after%navgraphentry}'
41 navgraph = '{before%navgraphentry}{after%navgraphentry}'
42 filenav = '{before%filenaventry}{after%filenaventry}'
42 filenav = '{before%filenaventry}{after%filenaventry}'
43
43
44 direntry = '
44 direntry = '
45 <tr class="fileline">
45 <tr class="fileline">
46 <td class="name">
46 <td class="name">
47 <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">
47 <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">
48 <img src="{staticurl|urlescape}coal-folder.png" alt="dir."/> {basename|escape}/
48 <img src="{staticurl|urlescape}coal-folder.png" alt="dir."/> {basename|escape}/
49 </a>
49 </a>
50 <a href="{url|urlescape}file/{symrev}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">
50 <a href="{url|urlescape}file/{symrev}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">
51 {emptydirs|escape}
51 {emptydirs|escape}
52 </a>
52 </a>
53 </td>
53 </td>
54 <td class="size"></td>
54 <td class="size"></td>
55 <td class="permissions">drwxr-xr-x</td>
55 <td class="permissions">drwxr-xr-x</td>
56 </tr>'
56 </tr>'
57
57
58 fileentry = '
58 fileentry = '
59 <tr class="fileline">
59 <tr class="fileline">
60 <td class="filename">
60 <td class="filename">
61 <a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">
61 <a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">
62 <img src="{staticurl|urlescape}coal-file.png" alt="file"/> {basename|escape}
62 <img src="{staticurl|urlescape}coal-file.png" alt="file"/> {basename|escape}
63 </a>
63 </a>
64 </td>
64 </td>
65 <td class="size">{size}</td>
65 <td class="size">{size}</td>
66 <td class="permissions">{permissions|permissions}</td>
66 <td class="permissions">{permissions|permissions}</td>
67 </tr>'
67 </tr>'
68
68
69 filerevision = filerevision.tmpl
69 filerevision = filerevision.tmpl
70 fileannotate = fileannotate.tmpl
70 fileannotate = fileannotate.tmpl
71 filediff = filediff.tmpl
71 filediff = filediff.tmpl
72 filecomparison = filecomparison.tmpl
72 filecomparison = filecomparison.tmpl
73 filelog = filelog.tmpl
73 filelog = filelog.tmpl
74 fileline = '
74 fileline = '
75 <span id="{lineid}">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
75 <span id="{lineid}">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
76 filelogentry = filelogentry.tmpl
76 filelogentry = filelogentry.tmpl
77
77
78 annotateline = '
78 annotateline = '
79 <tr id="{lineid}"{ifeq(node, originalnode, ' class="thisrev"')}>
79 <tr id="{lineid}"{ifeq(node, originalnode, ' class="thisrev"')}>
80 <td class="annotate">
80 <td class="annotate">
81 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
81 {if(blockhead,
82 title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
82 '<a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
83 title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>',
84 '')}
83 </td>
85 </td>
84 <td class="source"><a href="#{lineid}">{linenumber}</a> {line|escape}</td>
86 <td class="source"><a href="#{lineid}">{linenumber}</a> {line|escape}</td>
85 </tr>'
87 </tr>'
86
88
87 diffblock = '<div class="bottomline inc-lineno"><pre class="sourcelines wrap">{lines}</pre></div>'
89 diffblock = '<div class="bottomline inc-lineno"><pre class="sourcelines wrap">{lines}</pre></div>'
88 difflineplus = '
90 difflineplus = '
89 <span id="{lineid}" class="plusline">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
91 <span id="{lineid}" class="plusline">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
90 difflineminus = '
92 difflineminus = '
91 <span id="{lineid}" class="minusline">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
93 <span id="{lineid}" class="minusline">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
92 difflineat = '
94 difflineat = '
93 <span id="{lineid}" class="atline">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
95 <span id="{lineid}" class="atline">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
94 diffline = '
96 diffline = '
95 <span id="{lineid}">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
97 <span id="{lineid}">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
96
98
97 comparisonblock ='
99 comparisonblock ='
98 <tbody class="block">
100 <tbody class="block">
99 {lines}
101 {lines}
100 </tbody>'
102 </tbody>'
101 comparisonline = '
103 comparisonline = '
102 <tr id="{lineid}">
104 <tr id="{lineid}">
103 <td class="source {type}"><a href="#{lineid}">{leftlinenumber}</a> {leftline|escape}</td>
105 <td class="source {type}"><a href="#{lineid}">{leftlinenumber}</a> {leftline|escape}</td>
104 <td class="source {type}"><a href="#{lineid}">{rightlinenumber}</a> {rightline|escape}</td>
106 <td class="source {type}"><a href="#{lineid}">{rightlinenumber}</a> {rightline|escape}</td>
105 </tr>'
107 </tr>'
106
108
107 changelogparent = '
109 changelogparent = '
108 <tr>
110 <tr>
109 <th class="parent">parent {rev}:</th>
111 <th class="parent">parent {rev}:</th>
110 <td class="parent"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
112 <td class="parent"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
111 </tr>'
113 </tr>'
112
114
113 changesetparent = '<a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a> '
115 changesetparent = '<a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a> '
114
116
115 changesetparentdiff = '
117 changesetparentdiff = '
116 {changesetparent}
118 {changesetparent}
117 {ifeq(node, basenode, '(current diff)', '({difffrom})')}'
119 {ifeq(node, basenode, '(current diff)', '({difffrom})')}'
118
120
119 difffrom = '<a href="{url|urlescape}rev/{node|short}:{originalnode|short}{sessionvars%urlparameter}">diff</a>'
121 difffrom = '<a href="{url|urlescape}rev/{node|short}:{originalnode|short}{sessionvars%urlparameter}">diff</a>'
120
122
121 filerevparent = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a> '
123 filerevparent = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a> '
122 filerevchild = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a> '
124 filerevchild = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a> '
123
125
124 filerename = '{file|escape}@'
126 filerename = '{file|escape}@'
125 filelogrename = '
127 filelogrename = '
126 <span class="base">
128 <span class="base">
127 base
129 base
128 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
130 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
129 {file|escape}@{node|short}
131 {file|escape}@{node|short}
130 </a>
132 </a>
131 </span>'
133 </span>'
132 fileannotateparent = '
134 fileannotateparent = '
133 <tr>
135 <tr>
134 <td class="metatag">parent:</td>
136 <td class="metatag">parent:</td>
135 <td>
137 <td>
136 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
138 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
137 {rename%filerename}{node|short}
139 {rename%filerename}{node|short}
138 </a>
140 </a>
139 </td>
141 </td>
140 </tr>'
142 </tr>'
141 changesetchild = ' <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
143 changesetchild = ' <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
142 changelogchild = '
144 changelogchild = '
143 <tr>
145 <tr>
144 <th class="child">child</th>
146 <th class="child">child</th>
145 <td class="child">
147 <td class="child">
146 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
148 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
147 {node|short}
149 {node|short}
148 </a>
150 </a>
149 </td>
151 </td>
150 </tr>'
152 </tr>'
151 fileannotatechild = '
153 fileannotatechild = '
152 <tr>
154 <tr>
153 <td class="metatag">child:</td>
155 <td class="metatag">child:</td>
154 <td>
156 <td>
155 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
157 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
156 {node|short}
158 {node|short}
157 </a>
159 </a>
158 </td>
160 </td>
159 </tr>'
161 </tr>'
160 tags = tags.tmpl
162 tags = tags.tmpl
161 tagentry = '
163 tagentry = '
162 <tr class="tagEntry">
164 <tr class="tagEntry">
163 <td>
165 <td>
164 <a href="{url|urlescape}rev/{tag|revescape}{sessionvars%urlparameter}">
166 <a href="{url|urlescape}rev/{tag|revescape}{sessionvars%urlparameter}">
165 {tag|escape}
167 {tag|escape}
166 </a>
168 </a>
167 </td>
169 </td>
168 <td class="node">
170 <td class="node">
169 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
171 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
170 {node|short}
172 {node|short}
171 </a>
173 </a>
172 </td>
174 </td>
173 </tr>'
175 </tr>'
174 bookmarks = bookmarks.tmpl
176 bookmarks = bookmarks.tmpl
175 bookmarkentry = '
177 bookmarkentry = '
176 <tr class="tagEntry">
178 <tr class="tagEntry">
177 <td>
179 <td>
178 <a href="{url|urlescape}rev/{bookmark|revescape}{sessionvars%urlparameter}">
180 <a href="{url|urlescape}rev/{bookmark|revescape}{sessionvars%urlparameter}">
179 {bookmark|escape}
181 {bookmark|escape}
180 </a>
182 </a>
181 </td>
183 </td>
182 <td class="node">
184 <td class="node">
183 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
185 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
184 {node|short}
186 {node|short}
185 </a>
187 </a>
186 </td>
188 </td>
187 </tr>'
189 </tr>'
188 branches = branches.tmpl
190 branches = branches.tmpl
189 branchentry = '
191 branchentry = '
190 <tr class="tagEntry">
192 <tr class="tagEntry">
191 <td>
193 <td>
192 <a href="{url|urlescape}shortlog/{branch|revescape}{sessionvars%urlparameter}" class="{status}">
194 <a href="{url|urlescape}shortlog/{branch|revescape}{sessionvars%urlparameter}" class="{status}">
193 {branch|escape}
195 {branch|escape}
194 </a>
196 </a>
195 </td>
197 </td>
196 <td class="node">
198 <td class="node">
197 <a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}" class="{status}">
199 <a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}" class="{status}">
198 {node|short}
200 {node|short}
199 </a>
201 </a>
200 </td>
202 </td>
201 </tr>'
203 </tr>'
202 changelogtag = '<span class="tag">{name|escape}</span> '
204 changelogtag = '<span class="tag">{name|escape}</span> '
203 changesettag = '<span class="tag">{tag|escape}</span> '
205 changesettag = '<span class="tag">{tag|escape}</span> '
204 changesetbookmark = '<span class="tag">{bookmark|escape}</span> '
206 changesetbookmark = '<span class="tag">{bookmark|escape}</span> '
205 changelogbranchhead = '<span class="branchhead">{name|escape}</span> '
207 changelogbranchhead = '<span class="branchhead">{name|escape}</span> '
206 changelogbranchname = '<span class="branchname">{name|escape}</span> '
208 changelogbranchname = '<span class="branchname">{name|escape}</span> '
207
209
208 filediffparent = '
210 filediffparent = '
209 <tr>
211 <tr>
210 <th class="parent">parent {rev}:</th>
212 <th class="parent">parent {rev}:</th>
211 <td class="parent"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
213 <td class="parent"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
212 </tr>'
214 </tr>'
213 filelogparent = '
215 filelogparent = '
214 <tr>
216 <tr>
215 <th>parent {rev}:</th>
217 <th>parent {rev}:</th>
216 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
218 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
217 </tr>'
219 </tr>'
218 filediffchild = '
220 filediffchild = '
219 <tr>
221 <tr>
220 <th class="child">child {rev}:</th>
222 <th class="child">child {rev}:</th>
221 <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
223 <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
222 </td>
224 </td>
223 </tr>'
225 </tr>'
224 filelogchild = '
226 filelogchild = '
225 <tr>
227 <tr>
226 <th>child {rev}:</th>
228 <th>child {rev}:</th>
227 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
229 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
228 </tr>'
230 </tr>'
229
231
230 indexentry = '
232 indexentry = '
231 <tr>
233 <tr>
232 <td><a href="{url|urlescape}{sessionvars%urlparameter}">{name|escape}</a></td>
234 <td><a href="{url|urlescape}{sessionvars%urlparameter}">{name|escape}</a></td>
233 <td>{description}</td>
235 <td>{description}</td>
234 <td>{contact|obfuscate}</td>
236 <td>{contact|obfuscate}</td>
235 <td class="age">{lastchange|rfc822date}</td>
237 <td class="age">{lastchange|rfc822date}</td>
236 <td class="indexlinks">{archives%indexarchiveentry}</td>
238 <td class="indexlinks">{archives%indexarchiveentry}</td>
237 <td>
239 <td>
238 {if(isdirectory, '',
240 {if(isdirectory, '',
239 '<a href="{url|urlescape}atom-log" title="subscribe to repository atom feed">
241 '<a href="{url|urlescape}atom-log" title="subscribe to repository atom feed">
240 <img class="atom-logo" src="{staticurl|urlescape}feed-icon-14x14.png" alt="subscribe to repository atom feed">
242 <img class="atom-logo" src="{staticurl|urlescape}feed-icon-14x14.png" alt="subscribe to repository atom feed">
241 </a>'
243 </a>'
242 )}
244 )}
243 </td>
245 </td>
244 </tr>\n'
246 </tr>\n'
245 indexarchiveentry = '<a href="{url|urlescape}archive/{node|short}{extension|urlescape}">&nbsp;&darr;{type|escape}</a>'
247 indexarchiveentry = '<a href="{url|urlescape}archive/{node|short}{extension|urlescape}">&nbsp;&darr;{type|escape}</a>'
246 index = index.tmpl
248 index = index.tmpl
247 archiveentry = '
249 archiveentry = '
248 <li>
250 <li>
249 <a href="{url|urlescape}archive/{symrev}{extension|urlescape}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a>
251 <a href="{url|urlescape}archive/{symrev}{extension|urlescape}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a>
250 </li>'
252 </li>'
251 notfound = notfound.tmpl
253 notfound = notfound.tmpl
252 error = error.tmpl
254 error = error.tmpl
253 urlparameter = '{separator}{name}={value|urlescape}'
255 urlparameter = '{separator}{name}={value|urlescape}'
254 hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
256 hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
255 breadcrumb = '&gt; <a href="{url|urlescape}">{name|escape}</a> '
257 breadcrumb = '&gt; <a href="{url|urlescape}">{name|escape}</a> '
256
258
257 searchhint = 'Find changesets by keywords (author, files, the commit message), revision
259 searchhint = 'Find changesets by keywords (author, files, the commit message), revision
258 number or hash, or <a href="{url|urlescape}help/revsets">revset expression</a>.'
260 number or hash, or <a href="{url|urlescape}help/revsets">revset expression</a>.'
@@ -1,191 +1,193 b''
1 default = 'shortlog'
1 default = 'shortlog'
2 mimetype = 'text/html; charset={encoding}'
2 mimetype = 'text/html; charset={encoding}'
3 header = header.tmpl
3 header = header.tmpl
4 footer = footer.tmpl
4 footer = footer.tmpl
5 search = search.tmpl
5 search = search.tmpl
6 changelog = changelog.tmpl
6 changelog = changelog.tmpl
7 shortlog = shortlog.tmpl
7 shortlog = shortlog.tmpl
8 shortlogentry = shortlogentry.tmpl
8 shortlogentry = shortlogentry.tmpl
9 graph = graph.tmpl
9 graph = graph.tmpl
10 naventry = '<a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
10 naventry = '<a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
11 navshortentry = '<a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
11 navshortentry = '<a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
12 navgraphentry = '<a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
12 navgraphentry = '<a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
13 filenaventry = '<a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
13 filenaventry = '<a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
14 filedifflink = '<a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
14 filedifflink = '<a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
15 filenodelink = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
15 filenodelink = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
16 filenolink = '{file|escape} '
16 filenolink = '{file|escape} '
17 fileellipses = '...'
17 fileellipses = '...'
18 changelogentry = changelogentry.tmpl
18 changelogentry = changelogentry.tmpl
19 searchentry = changelogentry.tmpl
19 searchentry = changelogentry.tmpl
20 changeset = changeset.tmpl
20 changeset = changeset.tmpl
21 manifest = manifest.tmpl
21 manifest = manifest.tmpl
22
22
23 nav = '{before%naventry} {after%naventry}'
23 nav = '{before%naventry} {after%naventry}'
24 navshort = '{before%navshortentry}{after%navshortentry}'
24 navshort = '{before%navshortentry}{after%navshortentry}'
25 navgraph = '{before%navgraphentry}{after%navgraphentry}'
25 navgraph = '{before%navgraphentry}{after%navgraphentry}'
26 filenav = '{before%filenaventry}{after%filenaventry}'
26 filenav = '{before%filenaventry}{after%filenaventry}'
27
27
28 direntry = '
28 direntry = '
29 <tr class="parity{parity}">
29 <tr class="parity{parity}">
30 <td><tt>drwxr-xr-x</tt>&nbsp;
30 <td><tt>drwxr-xr-x</tt>&nbsp;
31 <td>&nbsp;
31 <td>&nbsp;
32 <td>&nbsp;
32 <td>&nbsp;
33 <td>
33 <td>
34 <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}/</a>
34 <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}/</a>
35 <a href="{url|urlescape}file/{symrev}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">
35 <a href="{url|urlescape}file/{symrev}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">
36 {emptydirs|urlescape}
36 {emptydirs|urlescape}
37 </a>'
37 </a>'
38
38
39 fileentry = '
39 fileentry = '
40 <tr class="parity{parity}">
40 <tr class="parity{parity}">
41 <td><tt>{permissions|permissions}</tt>&nbsp;
41 <td><tt>{permissions|permissions}</tt>&nbsp;
42 <td align=right><tt class="date">{date|isodate}</tt>&nbsp;
42 <td align=right><tt class="date">{date|isodate}</tt>&nbsp;
43 <td align=right><tt>{size}</tt>&nbsp;
43 <td align=right><tt>{size}</tt>&nbsp;
44 <td><a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>'
44 <td><a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>'
45
45
46 filerevision = filerevision.tmpl
46 filerevision = filerevision.tmpl
47 fileannotate = fileannotate.tmpl
47 fileannotate = fileannotate.tmpl
48 filediff = filediff.tmpl
48 filediff = filediff.tmpl
49 filelog = filelog.tmpl
49 filelog = filelog.tmpl
50 fileline = '<div class="parity{parity}"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>&nbsp;{line|escape}</div>'
50 fileline = '<div class="parity{parity}"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>&nbsp;{line|escape}</div>'
51 filelogentry = filelogentry.tmpl
51 filelogentry = filelogentry.tmpl
52
52
53 # The &nbsp; ensures that all table cells have content (even if there
53 # The &nbsp; ensures that all table cells have content (even if there
54 # is an empty line in the annotated file), which in turn ensures that
54 # is an empty line in the annotated file), which in turn ensures that
55 # all table rows have equal height.
55 # all table rows have equal height.
56 annotateline = '
56 annotateline = '
57 <tr class="parity{parity}{ifeq(node, originalnode, ' thisrev')}">
57 <tr class="parity{parity}{ifeq(node, originalnode, ' thisrev')}">
58 <td class="annotate">
58 <td class="annotate">
59 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
59 {if(blockhead,
60 title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
60 '<a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
61 title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>',
62 '')}
61 </td>
63 </td>
62 <td>
64 <td>
63 <a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>
65 <a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>
64 </td>
66 </td>
65 <td><pre>&nbsp;{line|escape}</pre></td>
67 <td><pre>&nbsp;{line|escape}</pre></td>
66 </tr>'
68 </tr>'
67 difflineplus = '<span class="plusline"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}</span>'
69 difflineplus = '<span class="plusline"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}</span>'
68 difflineminus = '<span class="minusline"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}</span>'
70 difflineminus = '<span class="minusline"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}</span>'
69 difflineat = '<span class="atline"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}</span>'
71 difflineat = '<span class="atline"><a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}</span>'
70 diffline = '<a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}'
72 diffline = '<a class="lineno" href="#{lineid}" id="{lineid}">{linenumber}</a>{line|escape}'
71 changesetlink = '<a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
73 changesetlink = '<a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
72 changelogparent = '
74 changelogparent = '
73 <tr>
75 <tr>
74 <th class="parent">parent {rev}:</th>
76 <th class="parent">parent {rev}:</th>
75 <td class="parent">
77 <td class="parent">
76 {changesetlink}
78 {changesetlink}
77 </td>
79 </td>
78 </tr>'
80 </tr>'
79 changesetparent = '
81 changesetparent = '
80 <tr>
82 <tr>
81 <th class="parent">parent {rev}:</th>
83 <th class="parent">parent {rev}:</th>
82 <td class="parent">{changesetlink}</td>
84 <td class="parent">{changesetlink}</td>
83 </tr>'
85 </tr>'
84 changesetparentdiff = '
86 changesetparentdiff = '
85 <tr>
87 <tr>
86 <th class="parent">parent {rev}:</th>
88 <th class="parent">parent {rev}:</th>
87 <td class="parent">{changesetlink} {ifeq(node, basenode, '(current diff)', '({difffrom})')}</td>
89 <td class="parent">{changesetlink} {ifeq(node, basenode, '(current diff)', '({difffrom})')}</td>
88 </tr>'
90 </tr>'
89 difffrom = '<a href="{url|urlescape}rev/{node|short}:{originalnode|short}{sessionvars%urlparameter}">diff</a>'
91 difffrom = '<a href="{url|urlescape}rev/{node|short}:{originalnode|short}{sessionvars%urlparameter}">diff</a>'
90 filerevparent = '
92 filerevparent = '
91 <tr>
93 <tr>
92 <td class="metatag">parent:</td>
94 <td class="metatag">parent:</td>
93 <td>
95 <td>
94 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
96 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
95 {rename%filerename}{node|short}
97 {rename%filerename}{node|short}
96 </a>
98 </a>
97 </td>
99 </td>
98 </tr>'
100 </tr>'
99 filerename = '{file|escape}@'
101 filerename = '{file|escape}@'
100 filelogrename = '
102 filelogrename = '
101 <tr>
103 <tr>
102 <th>base:</th>
104 <th>base:</th>
103 <td>
105 <td>
104 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
106 <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
105 {file|escape}@{node|short}
107 {file|escape}@{node|short}
106 </a>
108 </a>
107 </td>
109 </td>
108 </tr>'
110 </tr>'
109 fileannotateparent = '
111 fileannotateparent = '
110 <tr>
112 <tr>
111 <td class="metatag">parent:</td>
113 <td class="metatag">parent:</td>
112 <td>
114 <td>
113 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
115 <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
114 {rename%filerename}{node|short}
116 {rename%filerename}{node|short}
115 </a>
117 </a>
116 </td>
118 </td>
117 </tr>'
119 </tr>'
118 changesetchild = '
120 changesetchild = '
119 <tr>
121 <tr>
120 <th class="child">child {rev}:</th>
122 <th class="child">child {rev}:</th>
121 <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
123 <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
122 </tr>'
124 </tr>'
123 changelogchild = '
125 changelogchild = '
124 <tr>
126 <tr>
125 <th class="child">child {rev}:</th>
127 <th class="child">child {rev}:</th>
126 <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
128 <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
127 </tr>'
129 </tr>'
128 filerevchild = '
130 filerevchild = '
129 <tr>
131 <tr>
130 <td class="metatag">child:</td>
132 <td class="metatag">child:</td>
131 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
133 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
132 </tr>'
134 </tr>'
133 fileannotatechild = '
135 fileannotatechild = '
134 <tr>
136 <tr>
135 <td class="metatag">child:</td>
137 <td class="metatag">child:</td>
136 <td><a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
138 <td><a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
137 </tr>'
139 </tr>'
138 tags = tags.tmpl
140 tags = tags.tmpl
139 tagentry = '
141 tagentry = '
140 <li class="tagEntry parity{parity}">
142 <li class="tagEntry parity{parity}">
141 <tt class="node">{node}</tt>
143 <tt class="node">{node}</tt>
142 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{tag|escape}</a>
144 <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{tag|escape}</a>
143 </li>'
145 </li>'
144 branches = branches.tmpl
146 branches = branches.tmpl
145 branchentry = '
147 branchentry = '
146 <li class="tagEntry parity{parity}">
148 <li class="tagEntry parity{parity}">
147 <tt class="node">{node}</tt>
149 <tt class="node">{node}</tt>
148 <a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}" class="{status}">{branch|escape}</a>
150 <a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}" class="{status}">{branch|escape}</a>
149 </li>'
151 </li>'
150 diffblock = '<pre class="parity{parity}">{lines}</pre>'
152 diffblock = '<pre class="parity{parity}">{lines}</pre>'
151 changelogtag = '<tr><th class="tag">tag:</th><td class="tag">{tag|escape}</td></tr>'
153 changelogtag = '<tr><th class="tag">tag:</th><td class="tag">{tag|escape}</td></tr>'
152 changesettag = '<tr><th class="tag">tag:</th><td class="tag">{tag|escape}</td></tr>'
154 changesettag = '<tr><th class="tag">tag:</th><td class="tag">{tag|escape}</td></tr>'
153 filediffparent = '
155 filediffparent = '
154 <tr>
156 <tr>
155 <th class="parent">parent {rev}:</th>
157 <th class="parent">parent {rev}:</th>
156 <td class="parent"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
158 <td class="parent"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
157 </tr>'
159 </tr>'
158 filelogparent = '
160 filelogparent = '
159 <tr>
161 <tr>
160 <th>parent {rev}:</th>
162 <th>parent {rev}:</th>
161 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
163 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
162 </tr>'
164 </tr>'
163 filediffchild = '
165 filediffchild = '
164 <tr>
166 <tr>
165 <th class="child">child {rev}:</th>
167 <th class="child">child {rev}:</th>
166 <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
168 <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
167 </tr>'
169 </tr>'
168 filelogchild = '
170 filelogchild = '
169 <tr>
171 <tr>
170 <th>child {rev}:</th>
172 <th>child {rev}:</th>
171 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
173 <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
172 </tr>'
174 </tr>'
173 indexentry = '
175 indexentry = '
174 <tr class="parity{parity}">
176 <tr class="parity{parity}">
175 <td><a href="{url|urlescape}{sessionvars%urlparameter}">{name|escape}</a></td>
177 <td><a href="{url|urlescape}{sessionvars%urlparameter}">{name|escape}</a></td>
176 <td>{description}</td>
178 <td>{description}</td>
177 <td>{contact|obfuscate}</td>
179 <td>{contact|obfuscate}</td>
178 <td class="age">{lastchange|rfc822date}</td>
180 <td class="age">{lastchange|rfc822date}</td>
179 <td class="indexlinks">
181 <td class="indexlinks">
180 <a href="{url|urlescape}rss-log">RSS</a>
182 <a href="{url|urlescape}rss-log">RSS</a>
181 <a href="{url|urlescape}atom-log">Atom</a>
183 <a href="{url|urlescape}atom-log">Atom</a>
182 {archives%archiveentry}
184 {archives%archiveentry}
183 </td>
185 </td>
184 </tr>'
186 </tr>'
185 index = index.tmpl
187 index = index.tmpl
186 archiveentry = '<a href="{url|urlescape}archive/{symrev}{extension|urlescape}">{type|escape}</a> '
188 archiveentry = '<a href="{url|urlescape}archive/{symrev}{extension|urlescape}">{type|escape}</a> '
187 notfound = notfound.tmpl
189 notfound = notfound.tmpl
188 error = error.tmpl
190 error = error.tmpl
189 urlparameter = '{separator}{name}={value|urlescape}'
191 urlparameter = '{separator}{name}={value|urlescape}'
190 hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
192 hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
191 breadcrumb = '&gt; <a href="{url|urlescape}">{name|escape}</a> '
193 breadcrumb = '&gt; <a href="{url|urlescape}">{name|escape}</a> '
@@ -1,690 +1,658 b''
1 #require pygments serve
1 #require pygments serve
2
2
3 $ cat <<EOF >> $HGRCPATH
3 $ cat <<EOF >> $HGRCPATH
4 > [extensions]
4 > [extensions]
5 > highlight =
5 > highlight =
6 > [web]
6 > [web]
7 > pygments_style = friendly
7 > pygments_style = friendly
8 > highlightfiles = **.py and size('<100KB')
8 > highlightfiles = **.py and size('<100KB')
9 > EOF
9 > EOF
10 $ hg init test
10 $ hg init test
11 $ cd test
11 $ cd test
12
12
13 $ filterhtml () {
13 $ filterhtml () {
14 > sed -e "s/class=\"k\"/class=\"kn\"/g" \
14 > sed -e "s/class=\"k\"/class=\"kn\"/g" \
15 > -e "s/class=\"mf\"/class=\"mi\"/g" \
15 > -e "s/class=\"mf\"/class=\"mi\"/g" \
16 > -e "s/class=\"\([cs]\)[h12]\"/class=\"\1\"/g"
16 > -e "s/class=\"\([cs]\)[h12]\"/class=\"\1\"/g"
17 > }
17 > }
18
18
19 create random Python file to exercise Pygments
19 create random Python file to exercise Pygments
20
20
21 $ cat <<EOF > primes.py
21 $ cat <<EOF > primes.py
22 > #!/usr/bin/env python
22 > #!/usr/bin/env python
23 >
23 >
24 > """Fun with generators. Corresponding Haskell implementation:
24 > """Fun with generators. Corresponding Haskell implementation:
25 >
25 >
26 > primes = 2 : sieve [3, 5..]
26 > primes = 2 : sieve [3, 5..]
27 > where sieve (p:ns) = p : sieve [n | n <- ns, mod n p /= 0]
27 > where sieve (p:ns) = p : sieve [n | n <- ns, mod n p /= 0]
28 > """
28 > """
29 >
29 >
30 > from itertools import dropwhile, ifilter, islice, count, chain
30 > from itertools import dropwhile, ifilter, islice, count, chain
31 >
31 >
32 > def primes():
32 > def primes():
33 > """Generate all primes."""
33 > """Generate all primes."""
34 > def sieve(ns):
34 > def sieve(ns):
35 > p = ns.next()
35 > p = ns.next()
36 > # It is important to yield *here* in order to stop the
36 > # It is important to yield *here* in order to stop the
37 > # infinite recursion.
37 > # infinite recursion.
38 > yield p
38 > yield p
39 > ns = ifilter(lambda n: n % p != 0, ns)
39 > ns = ifilter(lambda n: n % p != 0, ns)
40 > for n in sieve(ns):
40 > for n in sieve(ns):
41 > yield n
41 > yield n
42 >
42 >
43 > odds = ifilter(lambda i: i % 2 == 1, count())
43 > odds = ifilter(lambda i: i % 2 == 1, count())
44 > return chain([2], sieve(dropwhile(lambda n: n < 3, odds)))
44 > return chain([2], sieve(dropwhile(lambda n: n < 3, odds)))
45 >
45 >
46 > if __name__ == "__main__":
46 > if __name__ == "__main__":
47 > import sys
47 > import sys
48 > try:
48 > try:
49 > n = int(sys.argv[1])
49 > n = int(sys.argv[1])
50 > except (ValueError, IndexError):
50 > except (ValueError, IndexError):
51 > n = 10
51 > n = 10
52 > p = primes()
52 > p = primes()
53 > print "The first %d primes: %s" % (n, list(islice(p, n)))
53 > print "The first %d primes: %s" % (n, list(islice(p, n)))
54 > EOF
54 > EOF
55 $ echo >> primes.py # to test html markup with an empty line just before EOF
55 $ echo >> primes.py # to test html markup with an empty line just before EOF
56 $ hg ci -Ama
56 $ hg ci -Ama
57 adding primes.py
57 adding primes.py
58
58
59 hg serve
59 hg serve
60
60
61 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
61 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
62 $ cat hg.pid >> $DAEMON_PIDS
62 $ cat hg.pid >> $DAEMON_PIDS
63
63
64 hgweb filerevision, html
64 hgweb filerevision, html
65
65
66 $ (get-with-headers.py localhost:$HGPORT 'file/tip/primes.py') | filterhtml
66 $ (get-with-headers.py localhost:$HGPORT 'file/tip/primes.py') | filterhtml
67 200 Script output follows
67 200 Script output follows
68
68
69 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
69 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
70 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
70 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
71 <head>
71 <head>
72 <link rel="icon" href="/static/hgicon.png" type="image/png" />
72 <link rel="icon" href="/static/hgicon.png" type="image/png" />
73 <meta name="robots" content="index, nofollow" />
73 <meta name="robots" content="index, nofollow" />
74 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
74 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
75 <script type="text/javascript" src="/static/mercurial.js"></script>
75 <script type="text/javascript" src="/static/mercurial.js"></script>
76
76
77 <link rel="stylesheet" href="/highlightcss" type="text/css" />
77 <link rel="stylesheet" href="/highlightcss" type="text/css" />
78 <title>test: 06824edf55d0 primes.py</title>
78 <title>test: 06824edf55d0 primes.py</title>
79 </head>
79 </head>
80 <body>
80 <body>
81
81
82 <div class="container">
82 <div class="container">
83 <div class="menu">
83 <div class="menu">
84 <div class="logo">
84 <div class="logo">
85 <a href="https://mercurial-scm.org/">
85 <a href="https://mercurial-scm.org/">
86 <img src="/static/hglogo.png" alt="mercurial" /></a>
86 <img src="/static/hglogo.png" alt="mercurial" /></a>
87 </div>
87 </div>
88 <ul>
88 <ul>
89 <li><a href="/shortlog/tip">log</a></li>
89 <li><a href="/shortlog/tip">log</a></li>
90 <li><a href="/graph/tip">graph</a></li>
90 <li><a href="/graph/tip">graph</a></li>
91 <li><a href="/tags">tags</a></li>
91 <li><a href="/tags">tags</a></li>
92 <li><a href="/bookmarks">bookmarks</a></li>
92 <li><a href="/bookmarks">bookmarks</a></li>
93 <li><a href="/branches">branches</a></li>
93 <li><a href="/branches">branches</a></li>
94 </ul>
94 </ul>
95 <ul>
95 <ul>
96 <li><a href="/rev/tip">changeset</a></li>
96 <li><a href="/rev/tip">changeset</a></li>
97 <li><a href="/file/tip/">browse</a></li>
97 <li><a href="/file/tip/">browse</a></li>
98 </ul>
98 </ul>
99 <ul>
99 <ul>
100 <li class="active">file</li>
100 <li class="active">file</li>
101 <li><a href="/file/tip/primes.py">latest</a></li>
101 <li><a href="/file/tip/primes.py">latest</a></li>
102 <li><a href="/diff/tip/primes.py">diff</a></li>
102 <li><a href="/diff/tip/primes.py">diff</a></li>
103 <li><a href="/comparison/tip/primes.py">comparison</a></li>
103 <li><a href="/comparison/tip/primes.py">comparison</a></li>
104 <li><a href="/annotate/tip/primes.py">annotate</a></li>
104 <li><a href="/annotate/tip/primes.py">annotate</a></li>
105 <li><a href="/log/tip/primes.py">file log</a></li>
105 <li><a href="/log/tip/primes.py">file log</a></li>
106 <li><a href="/raw-file/tip/primes.py">raw</a></li>
106 <li><a href="/raw-file/tip/primes.py">raw</a></li>
107 </ul>
107 </ul>
108 <ul>
108 <ul>
109 <li><a href="/help">help</a></li>
109 <li><a href="/help">help</a></li>
110 </ul>
110 </ul>
111 </div>
111 </div>
112
112
113 <div class="main">
113 <div class="main">
114 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
114 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
115 <h3>
115 <h3>
116 view primes.py @ 0:<a href="/rev/06824edf55d0">06824edf55d0</a>
116 view primes.py @ 0:<a href="/rev/06824edf55d0">06824edf55d0</a>
117 <span class="tag">tip</span>
117 <span class="tag">tip</span>
118 </h3>
118 </h3>
119
119
120 <form class="search" action="/log">
120 <form class="search" action="/log">
121
121
122 <p><input name="rev" id="search1" type="text" size="30" /></p>
122 <p><input name="rev" id="search1" type="text" size="30" /></p>
123 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
123 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
124 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
124 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
125 </form>
125 </form>
126
126
127 <div class="description">a</div>
127 <div class="description">a</div>
128
128
129 <table id="changesetEntry">
129 <table id="changesetEntry">
130 <tr>
130 <tr>
131 <th class="author">author</th>
131 <th class="author">author</th>
132 <td class="author">&#116;&#101;&#115;&#116;</td>
132 <td class="author">&#116;&#101;&#115;&#116;</td>
133 </tr>
133 </tr>
134 <tr>
134 <tr>
135 <th class="date">date</th>
135 <th class="date">date</th>
136 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
136 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
137 </tr>
137 </tr>
138 <tr>
138 <tr>
139 <th class="author">parents</th>
139 <th class="author">parents</th>
140 <td class="author"></td>
140 <td class="author"></td>
141 </tr>
141 </tr>
142 <tr>
142 <tr>
143 <th class="author">children</th>
143 <th class="author">children</th>
144 <td class="author"></td>
144 <td class="author"></td>
145 </tr>
145 </tr>
146 </table>
146 </table>
147
147
148 <div class="overflow">
148 <div class="overflow">
149 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
149 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
150 <div class="sourcefirst"> line source</div>
150 <div class="sourcefirst"> line source</div>
151 <pre class="sourcelines stripes4 wrap bottomline">
151 <pre class="sourcelines stripes4 wrap bottomline">
152 <span id="l1"><span class="c">#!/usr/bin/env python</span></span><a href="#l1"></a>
152 <span id="l1"><span class="c">#!/usr/bin/env python</span></span><a href="#l1"></a>
153 <span id="l2"></span><a href="#l2"></a>
153 <span id="l2"></span><a href="#l2"></a>
154 <span id="l3"><span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></span><a href="#l3"></a>
154 <span id="l3"><span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></span><a href="#l3"></a>
155 <span id="l4"></span><a href="#l4"></a>
155 <span id="l4"></span><a href="#l4"></a>
156 <span id="l5"><span class="sd">primes = 2 : sieve [3, 5..]</span></span><a href="#l5"></a>
156 <span id="l5"><span class="sd">primes = 2 : sieve [3, 5..]</span></span><a href="#l5"></a>
157 <span id="l6"><span class="sd"> where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></span><a href="#l6"></a>
157 <span id="l6"><span class="sd"> where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></span><a href="#l6"></a>
158 <span id="l7"><span class="sd">&quot;&quot;&quot;</span></span><a href="#l7"></a>
158 <span id="l7"><span class="sd">&quot;&quot;&quot;</span></span><a href="#l7"></a>
159 <span id="l8"></span><a href="#l8"></a>
159 <span id="l8"></span><a href="#l8"></a>
160 <span id="l9"><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">dropwhile</span><span class="p">,</span> <span class="n">ifilter</span><span class="p">,</span> <span class="n">islice</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">chain</span></span><a href="#l9"></a>
160 <span id="l9"><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">dropwhile</span><span class="p">,</span> <span class="n">ifilter</span><span class="p">,</span> <span class="n">islice</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">chain</span></span><a href="#l9"></a>
161 <span id="l10"></span><a href="#l10"></a>
161 <span id="l10"></span><a href="#l10"></a>
162 <span id="l11"><span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></span><a href="#l11"></a>
162 <span id="l11"><span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></span><a href="#l11"></a>
163 <span id="l12"> <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></span><a href="#l12"></a>
163 <span id="l12"> <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></span><a href="#l12"></a>
164 <span id="l13"> <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></span><a href="#l13"></a>
164 <span id="l13"> <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></span><a href="#l13"></a>
165 <span id="l14"> <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></span><a href="#l14"></a>
165 <span id="l14"> <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></span><a href="#l14"></a>
166 <span id="l15"> <span class="c"># It is important to yield *here* in order to stop the</span></span><a href="#l15"></a>
166 <span id="l15"> <span class="c"># It is important to yield *here* in order to stop the</span></span><a href="#l15"></a>
167 <span id="l16"> <span class="c"># infinite recursion.</span></span><a href="#l16"></a>
167 <span id="l16"> <span class="c"># infinite recursion.</span></span><a href="#l16"></a>
168 <span id="l17"> <span class="kn">yield</span> <span class="n">p</span></span><a href="#l17"></a>
168 <span id="l17"> <span class="kn">yield</span> <span class="n">p</span></span><a href="#l17"></a>
169 <span id="l18"> <span class="n">ns</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></span><a href="#l18"></a>
169 <span id="l18"> <span class="n">ns</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></span><a href="#l18"></a>
170 <span id="l19"> <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></span><a href="#l19"></a>
170 <span id="l19"> <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></span><a href="#l19"></a>
171 <span id="l20"> <span class="kn">yield</span> <span class="n">n</span></span><a href="#l20"></a>
171 <span id="l20"> <span class="kn">yield</span> <span class="n">n</span></span><a href="#l20"></a>
172 <span id="l21"></span><a href="#l21"></a>
172 <span id="l21"></span><a href="#l21"></a>
173 <span id="l22"> <span class="n">odds</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">count</span><span class="p">())</span></span><a href="#l22"></a>
173 <span id="l22"> <span class="n">odds</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">count</span><span class="p">())</span></span><a href="#l22"></a>
174 <span id="l23"> <span class="kn">return</span> <span class="n">chain</span><span class="p">([</span><span class="mi">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></span><a href="#l23"></a>
174 <span id="l23"> <span class="kn">return</span> <span class="n">chain</span><span class="p">([</span><span class="mi">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></span><a href="#l23"></a>
175 <span id="l24"></span><a href="#l24"></a>
175 <span id="l24"></span><a href="#l24"></a>
176 <span id="l25"><span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></span><a href="#l25"></a>
176 <span id="l25"><span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></span><a href="#l25"></a>
177 <span id="l26"> <span class="kn">import</span> <span class="nn">sys</span></span><a href="#l26"></a>
177 <span id="l26"> <span class="kn">import</span> <span class="nn">sys</span></span><a href="#l26"></a>
178 <span id="l27"> <span class="kn">try</span><span class="p">:</span></span><a href="#l27"></a>
178 <span id="l27"> <span class="kn">try</span><span class="p">:</span></span><a href="#l27"></a>
179 <span id="l28"> <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></span><a href="#l28"></a>
179 <span id="l28"> <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></span><a href="#l28"></a>
180 <span id="l29"> <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></span><a href="#l29"></a>
180 <span id="l29"> <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></span><a href="#l29"></a>
181 <span id="l30"> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></span><a href="#l30"></a>
181 <span id="l30"> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></span><a href="#l30"></a>
182 <span id="l31"> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></span><a href="#l31"></a>
182 <span id="l31"> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></span><a href="#l31"></a>
183 <span id="l32"> <span class="kn">print</span> <span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">)))</span></span><a href="#l32"></a>
183 <span id="l32"> <span class="kn">print</span> <span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">)))</span></span><a href="#l32"></a>
184 <span id="l33"></span><a href="#l33"></a></pre>
184 <span id="l33"></span><a href="#l33"></a></pre>
185 </div>
185 </div>
186 </div>
186 </div>
187 </div>
187 </div>
188
188
189 <script type="text/javascript">process_dates()</script>
189 <script type="text/javascript">process_dates()</script>
190
190
191
191
192 </body>
192 </body>
193 </html>
193 </html>
194
194
195
195
196 hgweb fileannotate, html
196 hgweb fileannotate, html
197
197
198 $ (get-with-headers.py localhost:$HGPORT 'annotate/tip/primes.py') | filterhtml
198 $ (get-with-headers.py localhost:$HGPORT 'annotate/tip/primes.py') | filterhtml
199 200 Script output follows
199 200 Script output follows
200
200
201 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
201 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
202 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
202 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
203 <head>
203 <head>
204 <link rel="icon" href="/static/hgicon.png" type="image/png" />
204 <link rel="icon" href="/static/hgicon.png" type="image/png" />
205 <meta name="robots" content="index, nofollow" />
205 <meta name="robots" content="index, nofollow" />
206 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
206 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
207 <script type="text/javascript" src="/static/mercurial.js"></script>
207 <script type="text/javascript" src="/static/mercurial.js"></script>
208
208
209 <link rel="stylesheet" href="/highlightcss" type="text/css" />
209 <link rel="stylesheet" href="/highlightcss" type="text/css" />
210 <title>test: primes.py annotate</title>
210 <title>test: primes.py annotate</title>
211 </head>
211 </head>
212 <body>
212 <body>
213
213
214 <div class="container">
214 <div class="container">
215 <div class="menu">
215 <div class="menu">
216 <div class="logo">
216 <div class="logo">
217 <a href="https://mercurial-scm.org/">
217 <a href="https://mercurial-scm.org/">
218 <img src="/static/hglogo.png" alt="mercurial" /></a>
218 <img src="/static/hglogo.png" alt="mercurial" /></a>
219 </div>
219 </div>
220 <ul>
220 <ul>
221 <li><a href="/shortlog/tip">log</a></li>
221 <li><a href="/shortlog/tip">log</a></li>
222 <li><a href="/graph/tip">graph</a></li>
222 <li><a href="/graph/tip">graph</a></li>
223 <li><a href="/tags">tags</a></li>
223 <li><a href="/tags">tags</a></li>
224 <li><a href="/bookmarks">bookmarks</a></li>
224 <li><a href="/bookmarks">bookmarks</a></li>
225 <li><a href="/branches">branches</a></li>
225 <li><a href="/branches">branches</a></li>
226 </ul>
226 </ul>
227
227
228 <ul>
228 <ul>
229 <li><a href="/rev/tip">changeset</a></li>
229 <li><a href="/rev/tip">changeset</a></li>
230 <li><a href="/file/tip/">browse</a></li>
230 <li><a href="/file/tip/">browse</a></li>
231 </ul>
231 </ul>
232 <ul>
232 <ul>
233 <li><a href="/file/tip/primes.py">file</a></li>
233 <li><a href="/file/tip/primes.py">file</a></li>
234 <li><a href="/file/tip/primes.py">latest</a></li>
234 <li><a href="/file/tip/primes.py">latest</a></li>
235 <li><a href="/diff/tip/primes.py">diff</a></li>
235 <li><a href="/diff/tip/primes.py">diff</a></li>
236 <li><a href="/comparison/tip/primes.py">comparison</a></li>
236 <li><a href="/comparison/tip/primes.py">comparison</a></li>
237 <li class="active">annotate</li>
237 <li class="active">annotate</li>
238 <li><a href="/log/tip/primes.py">file log</a></li>
238 <li><a href="/log/tip/primes.py">file log</a></li>
239 <li><a href="/raw-annotate/tip/primes.py">raw</a></li>
239 <li><a href="/raw-annotate/tip/primes.py">raw</a></li>
240 </ul>
240 </ul>
241 <ul>
241 <ul>
242 <li><a href="/help">help</a></li>
242 <li><a href="/help">help</a></li>
243 </ul>
243 </ul>
244 </div>
244 </div>
245
245
246 <div class="main">
246 <div class="main">
247 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
247 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
248 <h3>
248 <h3>
249 annotate primes.py @ 0:<a href="/rev/06824edf55d0">06824edf55d0</a>
249 annotate primes.py @ 0:<a href="/rev/06824edf55d0">06824edf55d0</a>
250 <span class="tag">tip</span>
250 <span class="tag">tip</span>
251 </h3>
251 </h3>
252
252
253 <form class="search" action="/log">
253 <form class="search" action="/log">
254
254
255 <p><input name="rev" id="search1" type="text" size="30" /></p>
255 <p><input name="rev" id="search1" type="text" size="30" /></p>
256 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
256 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
257 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
257 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
258 </form>
258 </form>
259
259
260 <div class="description">a</div>
260 <div class="description">a</div>
261
261
262 <table id="changesetEntry">
262 <table id="changesetEntry">
263 <tr>
263 <tr>
264 <th class="author">author</th>
264 <th class="author">author</th>
265 <td class="author">&#116;&#101;&#115;&#116;</td>
265 <td class="author">&#116;&#101;&#115;&#116;</td>
266 </tr>
266 </tr>
267 <tr>
267 <tr>
268 <th class="date">date</th>
268 <th class="date">date</th>
269 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
269 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
270 </tr>
270 </tr>
271 <tr>
271 <tr>
272 <th class="author">parents</th>
272 <th class="author">parents</th>
273 <td class="author"></td>
273 <td class="author"></td>
274 </tr>
274 </tr>
275 <tr>
275 <tr>
276 <th class="author">children</th>
276 <th class="author">children</th>
277 <td class="author"></td>
277 <td class="author"></td>
278 </tr>
278 </tr>
279 </table>
279 </table>
280
280
281 <div class="overflow">
281 <div class="overflow">
282 <table class="bigtable">
282 <table class="bigtable">
283 <thead>
283 <thead>
284 <tr>
284 <tr>
285 <th class="annotate">rev</th>
285 <th class="annotate">rev</th>
286 <th class="line">&nbsp;&nbsp;line source</th>
286 <th class="line">&nbsp;&nbsp;line source</th>
287 </tr>
287 </tr>
288 </thead>
288 </thead>
289 <tbody class="stripes2">
289 <tbody class="stripes2">
290
290
291 <tr id="l1" class="thisrev">
291 <tr id="l1" class="thisrev">
292 <td class="annotate">
292 <td class="annotate">
293 <a href="/annotate/06824edf55d0/primes.py#l1"
293 <a href="/annotate/06824edf55d0/primes.py#l1"
294 title="06824edf55d0: a">test@0</a>
294 title="06824edf55d0: a">test@0</a>
295 </td>
295 </td>
296 <td class="source"><a href="#l1"> 1</a> <span class="c">#!/usr/bin/env python</span></td>
296 <td class="source"><a href="#l1"> 1</a> <span class="c">#!/usr/bin/env python</span></td>
297 </tr>
297 </tr>
298 <tr id="l2" class="thisrev">
298 <tr id="l2" class="thisrev">
299 <td class="annotate">
299 <td class="annotate">
300 <a href="/annotate/06824edf55d0/primes.py#l2"
300
301 title="06824edf55d0: a">test@0</a>
302 </td>
301 </td>
303 <td class="source"><a href="#l2"> 2</a> </td>
302 <td class="source"><a href="#l2"> 2</a> </td>
304 </tr>
303 </tr>
305 <tr id="l3" class="thisrev">
304 <tr id="l3" class="thisrev">
306 <td class="annotate">
305 <td class="annotate">
307 <a href="/annotate/06824edf55d0/primes.py#l3"
306
308 title="06824edf55d0: a">test@0</a>
309 </td>
307 </td>
310 <td class="source"><a href="#l3"> 3</a> <span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></td>
308 <td class="source"><a href="#l3"> 3</a> <span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></td>
311 </tr>
309 </tr>
312 <tr id="l4" class="thisrev">
310 <tr id="l4" class="thisrev">
313 <td class="annotate">
311 <td class="annotate">
314 <a href="/annotate/06824edf55d0/primes.py#l4"
312
315 title="06824edf55d0: a">test@0</a>
316 </td>
313 </td>
317 <td class="source"><a href="#l4"> 4</a> </td>
314 <td class="source"><a href="#l4"> 4</a> </td>
318 </tr>
315 </tr>
319 <tr id="l5" class="thisrev">
316 <tr id="l5" class="thisrev">
320 <td class="annotate">
317 <td class="annotate">
321 <a href="/annotate/06824edf55d0/primes.py#l5"
318
322 title="06824edf55d0: a">test@0</a>
323 </td>
319 </td>
324 <td class="source"><a href="#l5"> 5</a> <span class="sd">primes = 2 : sieve [3, 5..]</span></td>
320 <td class="source"><a href="#l5"> 5</a> <span class="sd">primes = 2 : sieve [3, 5..]</span></td>
325 </tr>
321 </tr>
326 <tr id="l6" class="thisrev">
322 <tr id="l6" class="thisrev">
327 <td class="annotate">
323 <td class="annotate">
328 <a href="/annotate/06824edf55d0/primes.py#l6"
324
329 title="06824edf55d0: a">test@0</a>
330 </td>
325 </td>
331 <td class="source"><a href="#l6"> 6</a> <span class="sd"> where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></td>
326 <td class="source"><a href="#l6"> 6</a> <span class="sd"> where sieve (p:ns) = p : sieve [n | n &lt;- ns, mod n p /= 0]</span></td>
332 </tr>
327 </tr>
333 <tr id="l7" class="thisrev">
328 <tr id="l7" class="thisrev">
334 <td class="annotate">
329 <td class="annotate">
335 <a href="/annotate/06824edf55d0/primes.py#l7"
330
336 title="06824edf55d0: a">test@0</a>
337 </td>
331 </td>
338 <td class="source"><a href="#l7"> 7</a> <span class="sd">&quot;&quot;&quot;</span></td>
332 <td class="source"><a href="#l7"> 7</a> <span class="sd">&quot;&quot;&quot;</span></td>
339 </tr>
333 </tr>
340 <tr id="l8" class="thisrev">
334 <tr id="l8" class="thisrev">
341 <td class="annotate">
335 <td class="annotate">
342 <a href="/annotate/06824edf55d0/primes.py#l8"
336
343 title="06824edf55d0: a">test@0</a>
344 </td>
337 </td>
345 <td class="source"><a href="#l8"> 8</a> </td>
338 <td class="source"><a href="#l8"> 8</a> </td>
346 </tr>
339 </tr>
347 <tr id="l9" class="thisrev">
340 <tr id="l9" class="thisrev">
348 <td class="annotate">
341 <td class="annotate">
349 <a href="/annotate/06824edf55d0/primes.py#l9"
342
350 title="06824edf55d0: a">test@0</a>
351 </td>
343 </td>
352 <td class="source"><a href="#l9"> 9</a> <span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">dropwhile</span><span class="p">,</span> <span class="n">ifilter</span><span class="p">,</span> <span class="n">islice</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">chain</span></td>
344 <td class="source"><a href="#l9"> 9</a> <span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">dropwhile</span><span class="p">,</span> <span class="n">ifilter</span><span class="p">,</span> <span class="n">islice</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">chain</span></td>
353 </tr>
345 </tr>
354 <tr id="l10" class="thisrev">
346 <tr id="l10" class="thisrev">
355 <td class="annotate">
347 <td class="annotate">
356 <a href="/annotate/06824edf55d0/primes.py#l10"
348
357 title="06824edf55d0: a">test@0</a>
358 </td>
349 </td>
359 <td class="source"><a href="#l10"> 10</a> </td>
350 <td class="source"><a href="#l10"> 10</a> </td>
360 </tr>
351 </tr>
361 <tr id="l11" class="thisrev">
352 <tr id="l11" class="thisrev">
362 <td class="annotate">
353 <td class="annotate">
363 <a href="/annotate/06824edf55d0/primes.py#l11"
354
364 title="06824edf55d0: a">test@0</a>
365 </td>
355 </td>
366 <td class="source"><a href="#l11"> 11</a> <span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></td>
356 <td class="source"><a href="#l11"> 11</a> <span class="kn">def</span> <span class="nf">primes</span><span class="p">():</span></td>
367 </tr>
357 </tr>
368 <tr id="l12" class="thisrev">
358 <tr id="l12" class="thisrev">
369 <td class="annotate">
359 <td class="annotate">
370 <a href="/annotate/06824edf55d0/primes.py#l12"
360
371 title="06824edf55d0: a">test@0</a>
372 </td>
361 </td>
373 <td class="source"><a href="#l12"> 12</a> <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></td>
362 <td class="source"><a href="#l12"> 12</a> <span class="sd">&quot;&quot;&quot;Generate all primes.&quot;&quot;&quot;</span></td>
374 </tr>
363 </tr>
375 <tr id="l13" class="thisrev">
364 <tr id="l13" class="thisrev">
376 <td class="annotate">
365 <td class="annotate">
377 <a href="/annotate/06824edf55d0/primes.py#l13"
366
378 title="06824edf55d0: a">test@0</a>
379 </td>
367 </td>
380 <td class="source"><a href="#l13"> 13</a> <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
368 <td class="source"><a href="#l13"> 13</a> <span class="kn">def</span> <span class="nf">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
381 </tr>
369 </tr>
382 <tr id="l14" class="thisrev">
370 <tr id="l14" class="thisrev">
383 <td class="annotate">
371 <td class="annotate">
384 <a href="/annotate/06824edf55d0/primes.py#l14"
372
385 title="06824edf55d0: a">test@0</a>
386 </td>
373 </td>
387 <td class="source"><a href="#l14"> 14</a> <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></td>
374 <td class="source"><a href="#l14"> 14</a> <span class="n">p</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">next</span><span class="p">()</span></td>
388 </tr>
375 </tr>
389 <tr id="l15" class="thisrev">
376 <tr id="l15" class="thisrev">
390 <td class="annotate">
377 <td class="annotate">
391 <a href="/annotate/06824edf55d0/primes.py#l15"
378
392 title="06824edf55d0: a">test@0</a>
393 </td>
379 </td>
394 <td class="source"><a href="#l15"> 15</a> <span class="c"># It is important to yield *here* in order to stop the</span></td>
380 <td class="source"><a href="#l15"> 15</a> <span class="c"># It is important to yield *here* in order to stop the</span></td>
395 </tr>
381 </tr>
396 <tr id="l16" class="thisrev">
382 <tr id="l16" class="thisrev">
397 <td class="annotate">
383 <td class="annotate">
398 <a href="/annotate/06824edf55d0/primes.py#l16"
384
399 title="06824edf55d0: a">test@0</a>
400 </td>
385 </td>
401 <td class="source"><a href="#l16"> 16</a> <span class="c"># infinite recursion.</span></td>
386 <td class="source"><a href="#l16"> 16</a> <span class="c"># infinite recursion.</span></td>
402 </tr>
387 </tr>
403 <tr id="l17" class="thisrev">
388 <tr id="l17" class="thisrev">
404 <td class="annotate">
389 <td class="annotate">
405 <a href="/annotate/06824edf55d0/primes.py#l17"
390
406 title="06824edf55d0: a">test@0</a>
407 </td>
391 </td>
408 <td class="source"><a href="#l17"> 17</a> <span class="kn">yield</span> <span class="n">p</span></td>
392 <td class="source"><a href="#l17"> 17</a> <span class="kn">yield</span> <span class="n">p</span></td>
409 </tr>
393 </tr>
410 <tr id="l18" class="thisrev">
394 <tr id="l18" class="thisrev">
411 <td class="annotate">
395 <td class="annotate">
412 <a href="/annotate/06824edf55d0/primes.py#l18"
396
413 title="06824edf55d0: a">test@0</a>
414 </td>
397 </td>
415 <td class="source"><a href="#l18"> 18</a> <span class="n">ns</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></td>
398 <td class="source"><a href="#l18"> 18</a> <span class="n">ns</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ns</span><span class="p">)</span></td>
416 </tr>
399 </tr>
417 <tr id="l19" class="thisrev">
400 <tr id="l19" class="thisrev">
418 <td class="annotate">
401 <td class="annotate">
419 <a href="/annotate/06824edf55d0/primes.py#l19"
402
420 title="06824edf55d0: a">test@0</a>
421 </td>
403 </td>
422 <td class="source"><a href="#l19"> 19</a> <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
404 <td class="source"><a href="#l19"> 19</a> <span class="kn">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">sieve</span><span class="p">(</span><span class="n">ns</span><span class="p">):</span></td>
423 </tr>
405 </tr>
424 <tr id="l20" class="thisrev">
406 <tr id="l20" class="thisrev">
425 <td class="annotate">
407 <td class="annotate">
426 <a href="/annotate/06824edf55d0/primes.py#l20"
408
427 title="06824edf55d0: a">test@0</a>
428 </td>
409 </td>
429 <td class="source"><a href="#l20"> 20</a> <span class="kn">yield</span> <span class="n">n</span></td>
410 <td class="source"><a href="#l20"> 20</a> <span class="kn">yield</span> <span class="n">n</span></td>
430 </tr>
411 </tr>
431 <tr id="l21" class="thisrev">
412 <tr id="l21" class="thisrev">
432 <td class="annotate">
413 <td class="annotate">
433 <a href="/annotate/06824edf55d0/primes.py#l21"
414
434 title="06824edf55d0: a">test@0</a>
435 </td>
415 </td>
436 <td class="source"><a href="#l21"> 21</a> </td>
416 <td class="source"><a href="#l21"> 21</a> </td>
437 </tr>
417 </tr>
438 <tr id="l22" class="thisrev">
418 <tr id="l22" class="thisrev">
439 <td class="annotate">
419 <td class="annotate">
440 <a href="/annotate/06824edf55d0/primes.py#l22"
420
441 title="06824edf55d0: a">test@0</a>
442 </td>
421 </td>
443 <td class="source"><a href="#l22"> 22</a> <span class="n">odds</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">count</span><span class="p">())</span></td>
422 <td class="source"><a href="#l22"> 22</a> <span class="n">odds</span> <span class="o">=</span> <span class="n">ifilter</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">,</span> <span class="n">count</span><span class="p">())</span></td>
444 </tr>
423 </tr>
445 <tr id="l23" class="thisrev">
424 <tr id="l23" class="thisrev">
446 <td class="annotate">
425 <td class="annotate">
447 <a href="/annotate/06824edf55d0/primes.py#l23"
426
448 title="06824edf55d0: a">test@0</a>
449 </td>
427 </td>
450 <td class="source"><a href="#l23"> 23</a> <span class="kn">return</span> <span class="n">chain</span><span class="p">([</span><span class="mi">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></td>
428 <td class="source"><a href="#l23"> 23</a> <span class="kn">return</span> <span class="n">chain</span><span class="p">([</span><span class="mi">2</span><span class="p">],</span> <span class="n">sieve</span><span class="p">(</span><span class="n">dropwhile</span><span class="p">(</span><span class="kn">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">,</span> <span class="n">odds</span><span class="p">)))</span></td>
451 </tr>
429 </tr>
452 <tr id="l24" class="thisrev">
430 <tr id="l24" class="thisrev">
453 <td class="annotate">
431 <td class="annotate">
454 <a href="/annotate/06824edf55d0/primes.py#l24"
432
455 title="06824edf55d0: a">test@0</a>
456 </td>
433 </td>
457 <td class="source"><a href="#l24"> 24</a> </td>
434 <td class="source"><a href="#l24"> 24</a> </td>
458 </tr>
435 </tr>
459 <tr id="l25" class="thisrev">
436 <tr id="l25" class="thisrev">
460 <td class="annotate">
437 <td class="annotate">
461 <a href="/annotate/06824edf55d0/primes.py#l25"
438
462 title="06824edf55d0: a">test@0</a>
463 </td>
439 </td>
464 <td class="source"><a href="#l25"> 25</a> <span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></td>
440 <td class="source"><a href="#l25"> 25</a> <span class="kn">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span></td>
465 </tr>
441 </tr>
466 <tr id="l26" class="thisrev">
442 <tr id="l26" class="thisrev">
467 <td class="annotate">
443 <td class="annotate">
468 <a href="/annotate/06824edf55d0/primes.py#l26"
444
469 title="06824edf55d0: a">test@0</a>
470 </td>
445 </td>
471 <td class="source"><a href="#l26"> 26</a> <span class="kn">import</span> <span class="nn">sys</span></td>
446 <td class="source"><a href="#l26"> 26</a> <span class="kn">import</span> <span class="nn">sys</span></td>
472 </tr>
447 </tr>
473 <tr id="l27" class="thisrev">
448 <tr id="l27" class="thisrev">
474 <td class="annotate">
449 <td class="annotate">
475 <a href="/annotate/06824edf55d0/primes.py#l27"
450
476 title="06824edf55d0: a">test@0</a>
477 </td>
451 </td>
478 <td class="source"><a href="#l27"> 27</a> <span class="kn">try</span><span class="p">:</span></td>
452 <td class="source"><a href="#l27"> 27</a> <span class="kn">try</span><span class="p">:</span></td>
479 </tr>
453 </tr>
480 <tr id="l28" class="thisrev">
454 <tr id="l28" class="thisrev">
481 <td class="annotate">
455 <td class="annotate">
482 <a href="/annotate/06824edf55d0/primes.py#l28"
456
483 title="06824edf55d0: a">test@0</a>
484 </td>
457 </td>
485 <td class="source"><a href="#l28"> 28</a> <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></td>
458 <td class="source"><a href="#l28"> 28</a> <span class="n">n</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span></td>
486 </tr>
459 </tr>
487 <tr id="l29" class="thisrev">
460 <tr id="l29" class="thisrev">
488 <td class="annotate">
461 <td class="annotate">
489 <a href="/annotate/06824edf55d0/primes.py#l29"
462
490 title="06824edf55d0: a">test@0</a>
491 </td>
463 </td>
492 <td class="source"><a href="#l29"> 29</a> <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></td>
464 <td class="source"><a href="#l29"> 29</a> <span class="kn">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span></td>
493 </tr>
465 </tr>
494 <tr id="l30" class="thisrev">
466 <tr id="l30" class="thisrev">
495 <td class="annotate">
467 <td class="annotate">
496 <a href="/annotate/06824edf55d0/primes.py#l30"
468
497 title="06824edf55d0: a">test@0</a>
498 </td>
469 </td>
499 <td class="source"><a href="#l30"> 30</a> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></td>
470 <td class="source"><a href="#l30"> 30</a> <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span></td>
500 </tr>
471 </tr>
501 <tr id="l31" class="thisrev">
472 <tr id="l31" class="thisrev">
502 <td class="annotate">
473 <td class="annotate">
503 <a href="/annotate/06824edf55d0/primes.py#l31"
474
504 title="06824edf55d0: a">test@0</a>
505 </td>
475 </td>
506 <td class="source"><a href="#l31"> 31</a> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></td>
476 <td class="source"><a href="#l31"> 31</a> <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></td>
507 </tr>
477 </tr>
508 <tr id="l32" class="thisrev">
478 <tr id="l32" class="thisrev">
509 <td class="annotate">
479 <td class="annotate">
510 <a href="/annotate/06824edf55d0/primes.py#l32"
480
511 title="06824edf55d0: a">test@0</a>
512 </td>
481 </td>
513 <td class="source"><a href="#l32"> 32</a> <span class="kn">print</span> <span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">)))</span></td>
482 <td class="source"><a href="#l32"> 32</a> <span class="kn">print</span> <span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">)))</span></td>
514 </tr>
483 </tr>
515 <tr id="l33" class="thisrev">
484 <tr id="l33" class="thisrev">
516 <td class="annotate">
485 <td class="annotate">
517 <a href="/annotate/06824edf55d0/primes.py#l33"
486
518 title="06824edf55d0: a">test@0</a>
519 </td>
487 </td>
520 <td class="source"><a href="#l33"> 33</a> </td>
488 <td class="source"><a href="#l33"> 33</a> </td>
521 </tr>
489 </tr>
522 </tbody>
490 </tbody>
523 </table>
491 </table>
524 </div>
492 </div>
525 </div>
493 </div>
526 </div>
494 </div>
527
495
528 <script type="text/javascript">process_dates()</script>
496 <script type="text/javascript">process_dates()</script>
529
497
530
498
531 </body>
499 </body>
532 </html>
500 </html>
533
501
534
502
535 hgweb fileannotate, raw
503 hgweb fileannotate, raw
536
504
537 $ (get-with-headers.py localhost:$HGPORT 'annotate/tip/primes.py?style=raw') \
505 $ (get-with-headers.py localhost:$HGPORT 'annotate/tip/primes.py?style=raw') \
538 > | sed "s/test@//" > a
506 > | sed "s/test@//" > a
539 $ echo "200 Script output follows" > b
507 $ echo "200 Script output follows" > b
540 $ echo "" >> b
508 $ echo "" >> b
541 $ echo "" >> b
509 $ echo "" >> b
542 $ hg annotate "primes.py" >> b
510 $ hg annotate "primes.py" >> b
543 $ echo "" >> b
511 $ echo "" >> b
544 $ echo "" >> b
512 $ echo "" >> b
545 $ echo "" >> b
513 $ echo "" >> b
546 $ echo "" >> b
514 $ echo "" >> b
547 $ cmp b a || diff -u b a
515 $ cmp b a || diff -u b a
548
516
549 hgweb filerevision, raw
517 hgweb filerevision, raw
550
518
551 $ (get-with-headers.py localhost:$HGPORT 'file/tip/primes.py?style=raw') \
519 $ (get-with-headers.py localhost:$HGPORT 'file/tip/primes.py?style=raw') \
552 > > a
520 > > a
553 $ echo "200 Script output follows" > b
521 $ echo "200 Script output follows" > b
554 $ echo "" >> b
522 $ echo "" >> b
555 $ hg cat primes.py >> b
523 $ hg cat primes.py >> b
556 $ cmp b a || diff -u b a
524 $ cmp b a || diff -u b a
557
525
558 hgweb highlightcss friendly
526 hgweb highlightcss friendly
559
527
560 $ get-with-headers.py localhost:$HGPORT 'highlightcss' > out
528 $ get-with-headers.py localhost:$HGPORT 'highlightcss' > out
561 $ head -n 4 out
529 $ head -n 4 out
562 200 Script output follows
530 200 Script output follows
563
531
564 /* pygments_style = friendly */
532 /* pygments_style = friendly */
565
533
566 $ rm out
534 $ rm out
567
535
568 errors encountered
536 errors encountered
569
537
570 $ cat errors.log
538 $ cat errors.log
571 $ killdaemons.py
539 $ killdaemons.py
572
540
573 Change the pygments style
541 Change the pygments style
574
542
575 $ cat > .hg/hgrc <<EOF
543 $ cat > .hg/hgrc <<EOF
576 > [web]
544 > [web]
577 > pygments_style = fruity
545 > pygments_style = fruity
578 > EOF
546 > EOF
579
547
580 hg serve again
548 hg serve again
581
549
582 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
550 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
583 $ cat hg.pid >> $DAEMON_PIDS
551 $ cat hg.pid >> $DAEMON_PIDS
584
552
585 hgweb highlightcss fruity
553 hgweb highlightcss fruity
586
554
587 $ get-with-headers.py localhost:$HGPORT 'highlightcss' > out
555 $ get-with-headers.py localhost:$HGPORT 'highlightcss' > out
588 $ head -n 4 out
556 $ head -n 4 out
589 200 Script output follows
557 200 Script output follows
590
558
591 /* pygments_style = fruity */
559 /* pygments_style = fruity */
592
560
593 $ rm out
561 $ rm out
594
562
595 errors encountered
563 errors encountered
596
564
597 $ cat errors.log
565 $ cat errors.log
598 $ killdaemons.py
566 $ killdaemons.py
599
567
600 only highlight C source files
568 only highlight C source files
601
569
602 $ cat > .hg/hgrc <<EOF
570 $ cat > .hg/hgrc <<EOF
603 > [web]
571 > [web]
604 > highlightfiles = **.c
572 > highlightfiles = **.c
605 > EOF
573 > EOF
606
574
607 hg serve again
575 hg serve again
608
576
609 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
577 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
610 $ cat hg.pid >> $DAEMON_PIDS
578 $ cat hg.pid >> $DAEMON_PIDS
611
579
612 test that fileset in highlightfiles works and primes.py is not highlighted
580 test that fileset in highlightfiles works and primes.py is not highlighted
613
581
614 $ get-with-headers.py localhost:$HGPORT 'file/tip/primes.py' | grep 'id="l11"'
582 $ get-with-headers.py localhost:$HGPORT 'file/tip/primes.py' | grep 'id="l11"'
615 <span id="l11">def primes():</span><a href="#l11"></a>
583 <span id="l11">def primes():</span><a href="#l11"></a>
616
584
617 errors encountered
585 errors encountered
618
586
619 $ cat errors.log
587 $ cat errors.log
620 $ cd ..
588 $ cd ..
621 $ hg init eucjp
589 $ hg init eucjp
622 $ cd eucjp
590 $ cd eucjp
623 $ $PYTHON -c 'print("\265\376")' >> eucjp.txt # Japanese kanji "Kyo"
591 $ $PYTHON -c 'print("\265\376")' >> eucjp.txt # Japanese kanji "Kyo"
624 $ hg ci -Ama
592 $ hg ci -Ama
625 adding eucjp.txt
593 adding eucjp.txt
626 $ hgserveget () {
594 $ hgserveget () {
627 > killdaemons.py
595 > killdaemons.py
628 > echo % HGENCODING="$1" hg serve
596 > echo % HGENCODING="$1" hg serve
629 > HGENCODING="$1" hg serve -p $HGPORT -d -n test --pid-file=hg.pid -E errors.log
597 > HGENCODING="$1" hg serve -p $HGPORT -d -n test --pid-file=hg.pid -E errors.log
630 > cat hg.pid >> $DAEMON_PIDS
598 > cat hg.pid >> $DAEMON_PIDS
631 >
599 >
632 > echo % hgweb filerevision, html
600 > echo % hgweb filerevision, html
633 > get-with-headers.py localhost:$HGPORT "file/tip/$2" \
601 > get-with-headers.py localhost:$HGPORT "file/tip/$2" \
634 > | grep '<div class="parity0 source">'
602 > | grep '<div class="parity0 source">'
635 > echo % errors encountered
603 > echo % errors encountered
636 > cat errors.log
604 > cat errors.log
637 > }
605 > }
638 $ hgserveget euc-jp eucjp.txt
606 $ hgserveget euc-jp eucjp.txt
639 % HGENCODING=euc-jp hg serve
607 % HGENCODING=euc-jp hg serve
640 % hgweb filerevision, html
608 % hgweb filerevision, html
641 % errors encountered
609 % errors encountered
642 $ hgserveget utf-8 eucjp.txt
610 $ hgserveget utf-8 eucjp.txt
643 % HGENCODING=utf-8 hg serve
611 % HGENCODING=utf-8 hg serve
644 % hgweb filerevision, html
612 % hgweb filerevision, html
645 % errors encountered
613 % errors encountered
646 $ hgserveget us-ascii eucjp.txt
614 $ hgserveget us-ascii eucjp.txt
647 % HGENCODING=us-ascii hg serve
615 % HGENCODING=us-ascii hg serve
648 % hgweb filerevision, html
616 % hgweb filerevision, html
649 % errors encountered
617 % errors encountered
650
618
651 We attempt to highlight unknown files by default
619 We attempt to highlight unknown files by default
652
620
653 $ killdaemons.py
621 $ killdaemons.py
654
622
655 $ cat > .hg/hgrc << EOF
623 $ cat > .hg/hgrc << EOF
656 > [web]
624 > [web]
657 > highlightfiles = **
625 > highlightfiles = **
658 > EOF
626 > EOF
659
627
660 $ cat > unknownfile << EOF
628 $ cat > unknownfile << EOF
661 > #!/usr/bin/python
629 > #!/usr/bin/python
662 > def foo():
630 > def foo():
663 > pass
631 > pass
664 > EOF
632 > EOF
665
633
666 $ hg add unknownfile
634 $ hg add unknownfile
667 $ hg commit -m unknown unknownfile
635 $ hg commit -m unknown unknownfile
668
636
669 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid
637 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid
670 $ cat hg.pid >> $DAEMON_PIDS
638 $ cat hg.pid >> $DAEMON_PIDS
671
639
672 $ get-with-headers.py localhost:$HGPORT 'file/tip/unknownfile' | grep l2
640 $ get-with-headers.py localhost:$HGPORT 'file/tip/unknownfile' | grep l2
673 <span id="l2"><span class="k">def</span> <span class="nf">foo</span><span class="p">():</span></span><a href="#l2"></a>
641 <span id="l2"><span class="k">def</span> <span class="nf">foo</span><span class="p">():</span></span><a href="#l2"></a>
674
642
675 We can prevent Pygments from falling back to a non filename-based
643 We can prevent Pygments from falling back to a non filename-based
676 detection mode
644 detection mode
677
645
678 $ cat > .hg/hgrc << EOF
646 $ cat > .hg/hgrc << EOF
679 > [web]
647 > [web]
680 > highlightfiles = **
648 > highlightfiles = **
681 > highlightonlymatchfilename = true
649 > highlightonlymatchfilename = true
682 > EOF
650 > EOF
683
651
684 $ killdaemons.py
652 $ killdaemons.py
685 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid
653 $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid
686 $ cat hg.pid >> $DAEMON_PIDS
654 $ cat hg.pid >> $DAEMON_PIDS
687 $ get-with-headers.py localhost:$HGPORT 'file/tip/unknownfile' | grep l2
655 $ get-with-headers.py localhost:$HGPORT 'file/tip/unknownfile' | grep l2
688 <span id="l2">def foo():</span><a href="#l2"></a>
656 <span id="l2">def foo():</span><a href="#l2"></a>
689
657
690 $ cd ..
658 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now