##// END OF EJS Templates
hgweb: generate revnav in two phase...
Pierre-Yves David -
r18425:6da1e979 default
parent child Browse files
Show More
@@ -1,396 +1,402 b''
1 # hgweb/webutil.py - utility library for the web interface.
1 # hgweb/webutil.py - utility library for the web interface.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 import os, copy
9 import os, copy
10 from mercurial import match, patch, scmutil, error, ui, util
10 from mercurial import match, patch, scmutil, error, ui, util
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12 from mercurial.node import hex, nullid
12 from mercurial.node import hex, nullid
13 from common import ErrorResponse
13 from common import ErrorResponse
14 from common import HTTP_NOT_FOUND
14 from common import HTTP_NOT_FOUND
15 import difflib
15 import difflib
16
16
17 def up(p):
17 def up(p):
18 if p[0] != "/":
18 if p[0] != "/":
19 p = "/" + p
19 p = "/" + p
20 if p[-1] == "/":
20 if p[-1] == "/":
21 p = p[:-1]
21 p = p[:-1]
22 up = os.path.dirname(p)
22 up = os.path.dirname(p)
23 if up == "/":
23 if up == "/":
24 return "/"
24 return "/"
25 return up + "/"
25 return up + "/"
26
26
27 def _navseq(step, firststep=None):
27 def _navseq(step, firststep=None):
28 if firststep:
28 if firststep:
29 yield firststep
29 yield firststep
30 if firststep >= 20 and firststep <= 40:
30 if firststep >= 20 and firststep <= 40:
31 firststep = 50
31 firststep = 50
32 yield firststep
32 yield firststep
33 assert step > 0
33 assert step > 0
34 assert firststep > 0
34 assert firststep > 0
35 while step <= firststep:
35 while step <= firststep:
36 step *= 10
36 step *= 10
37 while True:
37 while True:
38 yield 1 * step
38 yield 1 * step
39 yield 3 * step
39 yield 3 * step
40 step *= 10
40 step *= 10
41
41
42 class revnav(object):
42 class revnav(object):
43
43
44 def __init__(self, repo):
44 def __init__(self, repo):
45 """Navigation generation object
45 """Navigation generation object
46
46
47 :repo: repo object we generate nav for
47 :repo: repo object we generate nav for
48 """
48 """
49 # used for hex generation
49 # used for hex generation
50 self._revlog = repo.changelog
50 self._revlog = repo.changelog
51
51
52 def __nonzero__(self):
52 def __nonzero__(self):
53 """return True if any revision to navigate over"""
53 """return True if any revision to navigate over"""
54 try:
54 try:
55 self._revlog.node(0)
55 self._revlog.node(0)
56 return True
56 return True
57 except error.RepoError:
57 except error.RepoError:
58 return False
58 return False
59
59
60 def hex(self, rev):
60 def hex(self, rev):
61 return hex(self._revlog.node(rev))
61 return hex(self._revlog.node(rev))
62
62
63 def gen(self, pos, pagelen, limit):
63 def gen(self, pos, pagelen, limit):
64 """computes label and revision id for navigation link
64 """computes label and revision id for navigation link
65
65
66 :pos: is the revision relative to which we generate navigation.
66 :pos: is the revision relative to which we generate navigation.
67 :pagelen: the size of each navigation page
67 :pagelen: the size of each navigation page
68 :limit: how far shall we link
68 :limit: how far shall we link
69
69
70 The return is:
70 The return is:
71 - a single element tuple
71 - a single element tuple
72 - containing a dictionary with a `before` and `after` key
72 - containing a dictionary with a `before` and `after` key
73 - values are generator functions taking arbitrary number of kwargs
73 - values are generator functions taking arbitrary number of kwargs
74 - yield items are dictionaries with `label` and `node` keys
74 - yield items are dictionaries with `label` and `node` keys
75 """
75 """
76 if not self:
76 if not self:
77 # empty repo
77 # empty repo
78 return ({'before': (), 'after': ()},)
78 return ({'before': (), 'after': ()},)
79
79
80 navbefore = [("(0)", self.hex(0))]
80 targets = []
81 navafter = []
82
83 for f in _navseq(1, pagelen):
81 for f in _navseq(1, pagelen):
84 if f > limit:
82 if f > limit:
85 break
83 break
86 if pos + f < limit:
84 targets.append(pos + f)
87 navafter.append(("+%d" % f, self.hex(pos + f)))
85 targets.append(pos - f)
88 if pos - f >= 0:
86 targets.sort()
89 navbefore.insert(0, ("-%d" % f, self.hex(pos - f)))
87
88 navbefore = [("(0)", self.hex(0))]
89 navafter = []
90 for rev in targets:
91 if pos < rev < limit:
92 navafter.append(("+%d" % f, self.hex(rev)))
93 if 0 < rev < pos:
94 navbefore.append(("-%d" % f, self.hex(rev)))
95
90
96
91 navafter.append(("tip", "tip"))
97 navafter.append(("tip", "tip"))
92
98
93 data = lambda i: {"label": i[0], "node": i[1]}
99 data = lambda i: {"label": i[0], "node": i[1]}
94 return ({'before': lambda **map: (data(i) for i in navbefore),
100 return ({'before': lambda **map: (data(i) for i in navbefore),
95 'after': lambda **map: (data(i) for i in navafter)},)
101 'after': lambda **map: (data(i) for i in navafter)},)
96
102
97 class filerevnav(revnav):
103 class filerevnav(revnav):
98
104
99 def __init__(self, repo, path):
105 def __init__(self, repo, path):
100 """Navigation generation object
106 """Navigation generation object
101
107
102 :repo: repo object we generate nav for
108 :repo: repo object we generate nav for
103 :path: path of the file we generate nav for
109 :path: path of the file we generate nav for
104 """
110 """
105 # used for iteration
111 # used for iteration
106 self._changelog = repo.unfiltered().changelog
112 self._changelog = repo.unfiltered().changelog
107 # used for hex generation
113 # used for hex generation
108 self._revlog = repo.file(path)
114 self._revlog = repo.file(path)
109
115
110 def hex(self, rev):
116 def hex(self, rev):
111 return hex(self._changelog.node(self._revlog.linkrev(rev)))
117 return hex(self._changelog.node(self._revlog.linkrev(rev)))
112
118
113
119
114 def _siblings(siblings=[], hiderev=None):
120 def _siblings(siblings=[], hiderev=None):
115 siblings = [s for s in siblings if s.node() != nullid]
121 siblings = [s for s in siblings if s.node() != nullid]
116 if len(siblings) == 1 and siblings[0].rev() == hiderev:
122 if len(siblings) == 1 and siblings[0].rev() == hiderev:
117 return
123 return
118 for s in siblings:
124 for s in siblings:
119 d = {'node': s.hex(), 'rev': s.rev()}
125 d = {'node': s.hex(), 'rev': s.rev()}
120 d['user'] = s.user()
126 d['user'] = s.user()
121 d['date'] = s.date()
127 d['date'] = s.date()
122 d['description'] = s.description()
128 d['description'] = s.description()
123 d['branch'] = s.branch()
129 d['branch'] = s.branch()
124 if util.safehasattr(s, 'path'):
130 if util.safehasattr(s, 'path'):
125 d['file'] = s.path()
131 d['file'] = s.path()
126 yield d
132 yield d
127
133
128 def parents(ctx, hide=None):
134 def parents(ctx, hide=None):
129 return _siblings(ctx.parents(), hide)
135 return _siblings(ctx.parents(), hide)
130
136
131 def children(ctx, hide=None):
137 def children(ctx, hide=None):
132 return _siblings(ctx.children(), hide)
138 return _siblings(ctx.children(), hide)
133
139
134 def renamelink(fctx):
140 def renamelink(fctx):
135 r = fctx.renamed()
141 r = fctx.renamed()
136 if r:
142 if r:
137 return [dict(file=r[0], node=hex(r[1]))]
143 return [dict(file=r[0], node=hex(r[1]))]
138 return []
144 return []
139
145
140 def nodetagsdict(repo, node):
146 def nodetagsdict(repo, node):
141 return [{"name": i} for i in repo.nodetags(node)]
147 return [{"name": i} for i in repo.nodetags(node)]
142
148
143 def nodebookmarksdict(repo, node):
149 def nodebookmarksdict(repo, node):
144 return [{"name": i} for i in repo.nodebookmarks(node)]
150 return [{"name": i} for i in repo.nodebookmarks(node)]
145
151
146 def nodebranchdict(repo, ctx):
152 def nodebranchdict(repo, ctx):
147 branches = []
153 branches = []
148 branch = ctx.branch()
154 branch = ctx.branch()
149 # If this is an empty repo, ctx.node() == nullid,
155 # If this is an empty repo, ctx.node() == nullid,
150 # ctx.branch() == 'default'.
156 # ctx.branch() == 'default'.
151 try:
157 try:
152 branchnode = repo.branchtip(branch)
158 branchnode = repo.branchtip(branch)
153 except error.RepoLookupError:
159 except error.RepoLookupError:
154 branchnode = None
160 branchnode = None
155 if branchnode == ctx.node():
161 if branchnode == ctx.node():
156 branches.append({"name": branch})
162 branches.append({"name": branch})
157 return branches
163 return branches
158
164
159 def nodeinbranch(repo, ctx):
165 def nodeinbranch(repo, ctx):
160 branches = []
166 branches = []
161 branch = ctx.branch()
167 branch = ctx.branch()
162 try:
168 try:
163 branchnode = repo.branchtip(branch)
169 branchnode = repo.branchtip(branch)
164 except error.RepoLookupError:
170 except error.RepoLookupError:
165 branchnode = None
171 branchnode = None
166 if branch != 'default' and branchnode != ctx.node():
172 if branch != 'default' and branchnode != ctx.node():
167 branches.append({"name": branch})
173 branches.append({"name": branch})
168 return branches
174 return branches
169
175
170 def nodebranchnodefault(ctx):
176 def nodebranchnodefault(ctx):
171 branches = []
177 branches = []
172 branch = ctx.branch()
178 branch = ctx.branch()
173 if branch != 'default':
179 if branch != 'default':
174 branches.append({"name": branch})
180 branches.append({"name": branch})
175 return branches
181 return branches
176
182
177 def showtag(repo, tmpl, t1, node=nullid, **args):
183 def showtag(repo, tmpl, t1, node=nullid, **args):
178 for t in repo.nodetags(node):
184 for t in repo.nodetags(node):
179 yield tmpl(t1, tag=t, **args)
185 yield tmpl(t1, tag=t, **args)
180
186
181 def showbookmark(repo, tmpl, t1, node=nullid, **args):
187 def showbookmark(repo, tmpl, t1, node=nullid, **args):
182 for t in repo.nodebookmarks(node):
188 for t in repo.nodebookmarks(node):
183 yield tmpl(t1, bookmark=t, **args)
189 yield tmpl(t1, bookmark=t, **args)
184
190
185 def cleanpath(repo, path):
191 def cleanpath(repo, path):
186 path = path.lstrip('/')
192 path = path.lstrip('/')
187 return scmutil.canonpath(repo.root, '', path)
193 return scmutil.canonpath(repo.root, '', path)
188
194
189 def changeidctx (repo, changeid):
195 def changeidctx (repo, changeid):
190 try:
196 try:
191 ctx = repo[changeid]
197 ctx = repo[changeid]
192 except error.RepoError:
198 except error.RepoError:
193 man = repo.manifest
199 man = repo.manifest
194 ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))]
200 ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))]
195
201
196 return ctx
202 return ctx
197
203
198 def changectx (repo, req):
204 def changectx (repo, req):
199 changeid = "tip"
205 changeid = "tip"
200 if 'node' in req.form:
206 if 'node' in req.form:
201 changeid = req.form['node'][0]
207 changeid = req.form['node'][0]
202 ipos=changeid.find(':')
208 ipos=changeid.find(':')
203 if ipos != -1:
209 if ipos != -1:
204 changeid = changeid[(ipos + 1):]
210 changeid = changeid[(ipos + 1):]
205 elif 'manifest' in req.form:
211 elif 'manifest' in req.form:
206 changeid = req.form['manifest'][0]
212 changeid = req.form['manifest'][0]
207
213
208 return changeidctx(repo, changeid)
214 return changeidctx(repo, changeid)
209
215
210 def basechangectx(repo, req):
216 def basechangectx(repo, req):
211 if 'node' in req.form:
217 if 'node' in req.form:
212 changeid = req.form['node'][0]
218 changeid = req.form['node'][0]
213 ipos=changeid.find(':')
219 ipos=changeid.find(':')
214 if ipos != -1:
220 if ipos != -1:
215 changeid = changeid[:ipos]
221 changeid = changeid[:ipos]
216 return changeidctx(repo, changeid)
222 return changeidctx(repo, changeid)
217
223
218 return None
224 return None
219
225
220 def filectx(repo, req):
226 def filectx(repo, req):
221 if 'file' not in req.form:
227 if 'file' not in req.form:
222 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
228 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
223 path = cleanpath(repo, req.form['file'][0])
229 path = cleanpath(repo, req.form['file'][0])
224 if 'node' in req.form:
230 if 'node' in req.form:
225 changeid = req.form['node'][0]
231 changeid = req.form['node'][0]
226 elif 'filenode' in req.form:
232 elif 'filenode' in req.form:
227 changeid = req.form['filenode'][0]
233 changeid = req.form['filenode'][0]
228 else:
234 else:
229 raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given')
235 raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given')
230 try:
236 try:
231 fctx = repo[changeid][path]
237 fctx = repo[changeid][path]
232 except error.RepoError:
238 except error.RepoError:
233 fctx = repo.filectx(path, fileid=changeid)
239 fctx = repo.filectx(path, fileid=changeid)
234
240
235 return fctx
241 return fctx
236
242
237 def listfilediffs(tmpl, files, node, max):
243 def listfilediffs(tmpl, files, node, max):
238 for f in files[:max]:
244 for f in files[:max]:
239 yield tmpl('filedifflink', node=hex(node), file=f)
245 yield tmpl('filedifflink', node=hex(node), file=f)
240 if len(files) > max:
246 if len(files) > max:
241 yield tmpl('fileellipses')
247 yield tmpl('fileellipses')
242
248
243 def diffs(repo, tmpl, ctx, basectx, files, parity, style):
249 def diffs(repo, tmpl, ctx, basectx, files, parity, style):
244
250
245 def countgen():
251 def countgen():
246 start = 1
252 start = 1
247 while True:
253 while True:
248 yield start
254 yield start
249 start += 1
255 start += 1
250
256
251 blockcount = countgen()
257 blockcount = countgen()
252 def prettyprintlines(diff, blockno):
258 def prettyprintlines(diff, blockno):
253 for lineno, l in enumerate(diff.splitlines(True)):
259 for lineno, l in enumerate(diff.splitlines(True)):
254 lineno = "%d.%d" % (blockno, lineno + 1)
260 lineno = "%d.%d" % (blockno, lineno + 1)
255 if l.startswith('+'):
261 if l.startswith('+'):
256 ltype = "difflineplus"
262 ltype = "difflineplus"
257 elif l.startswith('-'):
263 elif l.startswith('-'):
258 ltype = "difflineminus"
264 ltype = "difflineminus"
259 elif l.startswith('@'):
265 elif l.startswith('@'):
260 ltype = "difflineat"
266 ltype = "difflineat"
261 else:
267 else:
262 ltype = "diffline"
268 ltype = "diffline"
263 yield tmpl(ltype,
269 yield tmpl(ltype,
264 line=l,
270 line=l,
265 lineid="l%s" % lineno,
271 lineid="l%s" % lineno,
266 linenumber="% 8s" % lineno)
272 linenumber="% 8s" % lineno)
267
273
268 if files:
274 if files:
269 m = match.exact(repo.root, repo.getcwd(), files)
275 m = match.exact(repo.root, repo.getcwd(), files)
270 else:
276 else:
271 m = match.always(repo.root, repo.getcwd())
277 m = match.always(repo.root, repo.getcwd())
272
278
273 diffopts = patch.diffopts(repo.ui, untrusted=True)
279 diffopts = patch.diffopts(repo.ui, untrusted=True)
274 if basectx is None:
280 if basectx is None:
275 parents = ctx.parents()
281 parents = ctx.parents()
276 node1 = parents and parents[0].node() or nullid
282 node1 = parents and parents[0].node() or nullid
277 else:
283 else:
278 node1 = basectx.node()
284 node1 = basectx.node()
279 node2 = ctx.node()
285 node2 = ctx.node()
280
286
281 block = []
287 block = []
282 for chunk in patch.diff(repo, node1, node2, m, opts=diffopts):
288 for chunk in patch.diff(repo, node1, node2, m, opts=diffopts):
283 if chunk.startswith('diff') and block:
289 if chunk.startswith('diff') and block:
284 blockno = blockcount.next()
290 blockno = blockcount.next()
285 yield tmpl('diffblock', parity=parity.next(), blockno=blockno,
291 yield tmpl('diffblock', parity=parity.next(), blockno=blockno,
286 lines=prettyprintlines(''.join(block), blockno))
292 lines=prettyprintlines(''.join(block), blockno))
287 block = []
293 block = []
288 if chunk.startswith('diff') and style != 'raw':
294 if chunk.startswith('diff') and style != 'raw':
289 chunk = ''.join(chunk.splitlines(True)[1:])
295 chunk = ''.join(chunk.splitlines(True)[1:])
290 block.append(chunk)
296 block.append(chunk)
291 blockno = blockcount.next()
297 blockno = blockcount.next()
292 yield tmpl('diffblock', parity=parity.next(), blockno=blockno,
298 yield tmpl('diffblock', parity=parity.next(), blockno=blockno,
293 lines=prettyprintlines(''.join(block), blockno))
299 lines=prettyprintlines(''.join(block), blockno))
294
300
295 def compare(tmpl, context, leftlines, rightlines):
301 def compare(tmpl, context, leftlines, rightlines):
296 '''Generator function that provides side-by-side comparison data.'''
302 '''Generator function that provides side-by-side comparison data.'''
297
303
298 def compline(type, leftlineno, leftline, rightlineno, rightline):
304 def compline(type, leftlineno, leftline, rightlineno, rightline):
299 lineid = leftlineno and ("l%s" % leftlineno) or ''
305 lineid = leftlineno and ("l%s" % leftlineno) or ''
300 lineid += rightlineno and ("r%s" % rightlineno) or ''
306 lineid += rightlineno and ("r%s" % rightlineno) or ''
301 return tmpl('comparisonline',
307 return tmpl('comparisonline',
302 type=type,
308 type=type,
303 lineid=lineid,
309 lineid=lineid,
304 leftlinenumber="% 6s" % (leftlineno or ''),
310 leftlinenumber="% 6s" % (leftlineno or ''),
305 leftline=leftline or '',
311 leftline=leftline or '',
306 rightlinenumber="% 6s" % (rightlineno or ''),
312 rightlinenumber="% 6s" % (rightlineno or ''),
307 rightline=rightline or '')
313 rightline=rightline or '')
308
314
309 def getblock(opcodes):
315 def getblock(opcodes):
310 for type, llo, lhi, rlo, rhi in opcodes:
316 for type, llo, lhi, rlo, rhi in opcodes:
311 len1 = lhi - llo
317 len1 = lhi - llo
312 len2 = rhi - rlo
318 len2 = rhi - rlo
313 count = min(len1, len2)
319 count = min(len1, len2)
314 for i in xrange(count):
320 for i in xrange(count):
315 yield compline(type=type,
321 yield compline(type=type,
316 leftlineno=llo + i + 1,
322 leftlineno=llo + i + 1,
317 leftline=leftlines[llo + i],
323 leftline=leftlines[llo + i],
318 rightlineno=rlo + i + 1,
324 rightlineno=rlo + i + 1,
319 rightline=rightlines[rlo + i])
325 rightline=rightlines[rlo + i])
320 if len1 > len2:
326 if len1 > len2:
321 for i in xrange(llo + count, lhi):
327 for i in xrange(llo + count, lhi):
322 yield compline(type=type,
328 yield compline(type=type,
323 leftlineno=i + 1,
329 leftlineno=i + 1,
324 leftline=leftlines[i],
330 leftline=leftlines[i],
325 rightlineno=None,
331 rightlineno=None,
326 rightline=None)
332 rightline=None)
327 elif len2 > len1:
333 elif len2 > len1:
328 for i in xrange(rlo + count, rhi):
334 for i in xrange(rlo + count, rhi):
329 yield compline(type=type,
335 yield compline(type=type,
330 leftlineno=None,
336 leftlineno=None,
331 leftline=None,
337 leftline=None,
332 rightlineno=i + 1,
338 rightlineno=i + 1,
333 rightline=rightlines[i])
339 rightline=rightlines[i])
334
340
335 s = difflib.SequenceMatcher(None, leftlines, rightlines)
341 s = difflib.SequenceMatcher(None, leftlines, rightlines)
336 if context < 0:
342 if context < 0:
337 yield tmpl('comparisonblock', lines=getblock(s.get_opcodes()))
343 yield tmpl('comparisonblock', lines=getblock(s.get_opcodes()))
338 else:
344 else:
339 for oc in s.get_grouped_opcodes(n=context):
345 for oc in s.get_grouped_opcodes(n=context):
340 yield tmpl('comparisonblock', lines=getblock(oc))
346 yield tmpl('comparisonblock', lines=getblock(oc))
341
347
342 def diffstatgen(ctx, basectx):
348 def diffstatgen(ctx, basectx):
343 '''Generator function that provides the diffstat data.'''
349 '''Generator function that provides the diffstat data.'''
344
350
345 stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx)))
351 stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx)))
346 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
352 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
347 while True:
353 while True:
348 yield stats, maxname, maxtotal, addtotal, removetotal, binary
354 yield stats, maxname, maxtotal, addtotal, removetotal, binary
349
355
350 def diffsummary(statgen):
356 def diffsummary(statgen):
351 '''Return a short summary of the diff.'''
357 '''Return a short summary of the diff.'''
352
358
353 stats, maxname, maxtotal, addtotal, removetotal, binary = statgen.next()
359 stats, maxname, maxtotal, addtotal, removetotal, binary = statgen.next()
354 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % (
360 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % (
355 len(stats), addtotal, removetotal)
361 len(stats), addtotal, removetotal)
356
362
357 def diffstat(tmpl, ctx, statgen, parity):
363 def diffstat(tmpl, ctx, statgen, parity):
358 '''Return a diffstat template for each file in the diff.'''
364 '''Return a diffstat template for each file in the diff.'''
359
365
360 stats, maxname, maxtotal, addtotal, removetotal, binary = statgen.next()
366 stats, maxname, maxtotal, addtotal, removetotal, binary = statgen.next()
361 files = ctx.files()
367 files = ctx.files()
362
368
363 def pct(i):
369 def pct(i):
364 if maxtotal == 0:
370 if maxtotal == 0:
365 return 0
371 return 0
366 return (float(i) / maxtotal) * 100
372 return (float(i) / maxtotal) * 100
367
373
368 fileno = 0
374 fileno = 0
369 for filename, adds, removes, isbinary in stats:
375 for filename, adds, removes, isbinary in stats:
370 template = filename in files and 'diffstatlink' or 'diffstatnolink'
376 template = filename in files and 'diffstatlink' or 'diffstatnolink'
371 total = adds + removes
377 total = adds + removes
372 fileno += 1
378 fileno += 1
373 yield tmpl(template, node=ctx.hex(), file=filename, fileno=fileno,
379 yield tmpl(template, node=ctx.hex(), file=filename, fileno=fileno,
374 total=total, addpct=pct(adds), removepct=pct(removes),
380 total=total, addpct=pct(adds), removepct=pct(removes),
375 parity=parity.next())
381 parity=parity.next())
376
382
377 class sessionvars(object):
383 class sessionvars(object):
378 def __init__(self, vars, start='?'):
384 def __init__(self, vars, start='?'):
379 self.start = start
385 self.start = start
380 self.vars = vars
386 self.vars = vars
381 def __getitem__(self, key):
387 def __getitem__(self, key):
382 return self.vars[key]
388 return self.vars[key]
383 def __setitem__(self, key, value):
389 def __setitem__(self, key, value):
384 self.vars[key] = value
390 self.vars[key] = value
385 def __copy__(self):
391 def __copy__(self):
386 return sessionvars(copy.copy(self.vars), self.start)
392 return sessionvars(copy.copy(self.vars), self.start)
387 def __iter__(self):
393 def __iter__(self):
388 separator = self.start
394 separator = self.start
389 for key, value in sorted(self.vars.iteritems()):
395 for key, value in sorted(self.vars.iteritems()):
390 yield {'name': key, 'value': str(value), 'separator': separator}
396 yield {'name': key, 'value': str(value), 'separator': separator}
391 separator = '&'
397 separator = '&'
392
398
393 class wsgiui(ui.ui):
399 class wsgiui(ui.ui):
394 # default termwidth breaks under mod_wsgi
400 # default termwidth breaks under mod_wsgi
395 def termwidth(self):
401 def termwidth(self):
396 return 80
402 return 80
General Comments 0
You need to be logged in to leave comments. Login now