##// END OF EJS Templates
templater: rewrite doc of _hybrid class as docstring
Yuya Nishihara -
r31879:868ec199 default
parent child Browse files
Show More
@@ -1,646 +1,649 b''
1 1 # templatekw.py - common changeset template keywords
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 from .i18n import _
11 11 from .node import hex, nullid
12 12 from . import (
13 13 encoding,
14 14 error,
15 15 hbisect,
16 16 patch,
17 17 registrar,
18 18 scmutil,
19 19 util,
20 20 )
21 21
22 # This helper class allows us to handle both:
23 # "{files}" (legacy command-line-specific list hack) and
24 # "{files % '{file}\n'}" (hgweb-style with inlining and function support)
25 # and to access raw values:
26 # "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
27 # "{get(extras, key)}"
22 class _hybrid(object):
23 """Wrapper for list or dict to support legacy template
28 24
29 class _hybrid(object):
25 This class allows us to handle both:
26 - "{files}" (legacy command-line-specific list hack) and
27 - "{files % '{file}\n'}" (hgweb-style with inlining and function support)
28 and to access raw values:
29 - "{ifcontains(file, files, ...)}", "{ifcontains(key, extras, ...)}"
30 - "{get(extras, key)}"
31 """
32
30 33 def __init__(self, gen, values, makemap, joinfmt):
31 34 self.gen = gen
32 35 self.values = values
33 36 self._makemap = makemap
34 37 self.joinfmt = joinfmt
35 38 def __iter__(self):
36 39 return self.gen
37 40 def itermaps(self):
38 41 makemap = self._makemap
39 42 for x in self.values:
40 43 yield makemap(x)
41 44 def __contains__(self, x):
42 45 return x in self.values
43 46 def __len__(self):
44 47 return len(self.values)
45 48 def __getattr__(self, name):
46 49 if name != 'get':
47 50 raise AttributeError(name)
48 51 return getattr(self.values, name)
49 52
50 53 def showlist(name, values, plural=None, element=None, separator=' ', **args):
51 54 if not element:
52 55 element = name
53 56 f = _showlist(name, values, plural, separator, **args)
54 57 return _hybrid(f, values, lambda x: {element: x}, lambda d: d[element])
55 58
56 59 def _showlist(name, values, plural=None, separator=' ', **args):
57 60 '''expand set of values.
58 61 name is name of key in template map.
59 62 values is list of strings or dicts.
60 63 plural is plural of name, if not simply name + 's'.
61 64 separator is used to join values as a string
62 65
63 66 expansion works like this, given name 'foo'.
64 67
65 68 if values is empty, expand 'no_foos'.
66 69
67 70 if 'foo' not in template map, return values as a string,
68 71 joined by 'separator'.
69 72
70 73 expand 'start_foos'.
71 74
72 75 for each value, expand 'foo'. if 'last_foo' in template
73 76 map, expand it instead of 'foo' for last key.
74 77
75 78 expand 'end_foos'.
76 79 '''
77 80 templ = args['templ']
78 81 if plural:
79 82 names = plural
80 83 else: names = name + 's'
81 84 if not values:
82 85 noname = 'no_' + names
83 86 if noname in templ:
84 87 yield templ(noname, **args)
85 88 return
86 89 if name not in templ:
87 90 if isinstance(values[0], str):
88 91 yield separator.join(values)
89 92 else:
90 93 for v in values:
91 94 yield dict(v, **args)
92 95 return
93 96 startname = 'start_' + names
94 97 if startname in templ:
95 98 yield templ(startname, **args)
96 99 vargs = args.copy()
97 100 def one(v, tag=name):
98 101 try:
99 102 vargs.update(v)
100 103 except (AttributeError, ValueError):
101 104 try:
102 105 for a, b in v:
103 106 vargs[a] = b
104 107 except ValueError:
105 108 vargs[name] = v
106 109 return templ(tag, **vargs)
107 110 lastname = 'last_' + name
108 111 if lastname in templ:
109 112 last = values.pop()
110 113 else:
111 114 last = None
112 115 for v in values:
113 116 yield one(v)
114 117 if last is not None:
115 118 yield one(last, tag=lastname)
116 119 endname = 'end_' + names
117 120 if endname in templ:
118 121 yield templ(endname, **args)
119 122
120 123 def _formatrevnode(ctx):
121 124 """Format changeset as '{rev}:{node|formatnode}', which is the default
122 125 template provided by cmdutil.changeset_templater"""
123 126 repo = ctx.repo()
124 127 if repo.ui.debugflag:
125 128 hexnode = ctx.hex()
126 129 else:
127 130 hexnode = ctx.hex()[:12]
128 131 return '%d:%s' % (scmutil.intrev(ctx.rev()), hexnode)
129 132
130 133 def getfiles(repo, ctx, revcache):
131 134 if 'files' not in revcache:
132 135 revcache['files'] = repo.status(ctx.p1(), ctx)[:3]
133 136 return revcache['files']
134 137
135 138 def getlatesttags(repo, ctx, cache, pattern=None):
136 139 '''return date, distance and name for the latest tag of rev'''
137 140
138 141 cachename = 'latesttags'
139 142 if pattern is not None:
140 143 cachename += '-' + pattern
141 144 match = util.stringmatcher(pattern)[2]
142 145 else:
143 146 match = util.always
144 147
145 148 if cachename not in cache:
146 149 # Cache mapping from rev to a tuple with tag date, tag
147 150 # distance and tag name
148 151 cache[cachename] = {-1: (0, 0, ['null'])}
149 152 latesttags = cache[cachename]
150 153
151 154 rev = ctx.rev()
152 155 todo = [rev]
153 156 while todo:
154 157 rev = todo.pop()
155 158 if rev in latesttags:
156 159 continue
157 160 ctx = repo[rev]
158 161 tags = [t for t in ctx.tags()
159 162 if (repo.tagtype(t) and repo.tagtype(t) != 'local'
160 163 and match(t))]
161 164 if tags:
162 165 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
163 166 continue
164 167 try:
165 168 # The tuples are laid out so the right one can be found by
166 169 # comparison.
167 170 pdate, pdist, ptag = max(
168 171 latesttags[p.rev()] for p in ctx.parents())
169 172 except KeyError:
170 173 # Cache miss - recurse
171 174 todo.append(rev)
172 175 todo.extend(p.rev() for p in ctx.parents())
173 176 continue
174 177 latesttags[rev] = pdate, pdist + 1, ptag
175 178 return latesttags[rev]
176 179
177 180 def getrenamedfn(repo, endrev=None):
178 181 rcache = {}
179 182 if endrev is None:
180 183 endrev = len(repo)
181 184
182 185 def getrenamed(fn, rev):
183 186 '''looks up all renames for a file (up to endrev) the first
184 187 time the file is given. It indexes on the changerev and only
185 188 parses the manifest if linkrev != changerev.
186 189 Returns rename info for fn at changerev rev.'''
187 190 if fn not in rcache:
188 191 rcache[fn] = {}
189 192 fl = repo.file(fn)
190 193 for i in fl:
191 194 lr = fl.linkrev(i)
192 195 renamed = fl.renamed(fl.node(i))
193 196 rcache[fn][lr] = renamed
194 197 if lr >= endrev:
195 198 break
196 199 if rev in rcache[fn]:
197 200 return rcache[fn][rev]
198 201
199 202 # If linkrev != rev (i.e. rev not found in rcache) fallback to
200 203 # filectx logic.
201 204 try:
202 205 return repo[rev][fn].renamed()
203 206 except error.LookupError:
204 207 return None
205 208
206 209 return getrenamed
207 210
208 211 # default templates internally used for rendering of lists
209 212 defaulttempl = {
210 213 'parent': '{rev}:{node|formatnode} ',
211 214 'manifest': '{rev}:{node|formatnode}',
212 215 'file_copy': '{name} ({source})',
213 216 'envvar': '{key}={value}',
214 217 'extra': '{key}={value|stringescape}'
215 218 }
216 219 # filecopy is preserved for compatibility reasons
217 220 defaulttempl['filecopy'] = defaulttempl['file_copy']
218 221
219 222 # keywords are callables like:
220 223 # fn(repo, ctx, templ, cache, revcache, **args)
221 224 # with:
222 225 # repo - current repository instance
223 226 # ctx - the changectx being displayed
224 227 # templ - the templater instance
225 228 # cache - a cache dictionary for the whole templater run
226 229 # revcache - a cache dictionary for the current revision
227 230 keywords = {}
228 231
229 232 templatekeyword = registrar.templatekeyword(keywords)
230 233
231 234 @templatekeyword('author')
232 235 def showauthor(repo, ctx, templ, **args):
233 236 """String. The unmodified author of the changeset."""
234 237 return ctx.user()
235 238
236 239 @templatekeyword('bisect')
237 240 def showbisect(repo, ctx, templ, **args):
238 241 """String. The changeset bisection status."""
239 242 return hbisect.label(repo, ctx.node())
240 243
241 244 @templatekeyword('branch')
242 245 def showbranch(**args):
243 246 """String. The name of the branch on which the changeset was
244 247 committed.
245 248 """
246 249 return args['ctx'].branch()
247 250
248 251 @templatekeyword('branches')
249 252 def showbranches(**args):
250 253 """List of strings. The name of the branch on which the
251 254 changeset was committed. Will be empty if the branch name was
252 255 default. (DEPRECATED)
253 256 """
254 257 branch = args['ctx'].branch()
255 258 if branch != 'default':
256 259 return showlist('branch', [branch], plural='branches', **args)
257 260 return showlist('branch', [], plural='branches', **args)
258 261
259 262 @templatekeyword('bookmarks')
260 263 def showbookmarks(**args):
261 264 """List of strings. Any bookmarks associated with the
262 265 changeset. Also sets 'active', the name of the active bookmark.
263 266 """
264 267 repo = args['ctx']._repo
265 268 bookmarks = args['ctx'].bookmarks()
266 269 active = repo._activebookmark
267 270 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
268 271 f = _showlist('bookmark', bookmarks, **args)
269 272 return _hybrid(f, bookmarks, makemap, lambda x: x['bookmark'])
270 273
271 274 @templatekeyword('children')
272 275 def showchildren(**args):
273 276 """List of strings. The children of the changeset."""
274 277 ctx = args['ctx']
275 278 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
276 279 return showlist('children', childrevs, element='child', **args)
277 280
278 281 # Deprecated, but kept alive for help generation a purpose.
279 282 @templatekeyword('currentbookmark')
280 283 def showcurrentbookmark(**args):
281 284 """String. The active bookmark, if it is
282 285 associated with the changeset (DEPRECATED)"""
283 286 return showactivebookmark(**args)
284 287
285 288 @templatekeyword('activebookmark')
286 289 def showactivebookmark(**args):
287 290 """String. The active bookmark, if it is
288 291 associated with the changeset"""
289 292 active = args['repo']._activebookmark
290 293 if active and active in args['ctx'].bookmarks():
291 294 return active
292 295 return ''
293 296
294 297 @templatekeyword('date')
295 298 def showdate(repo, ctx, templ, **args):
296 299 """Date information. The date when the changeset was committed."""
297 300 return ctx.date()
298 301
299 302 @templatekeyword('desc')
300 303 def showdescription(repo, ctx, templ, **args):
301 304 """String. The text of the changeset description."""
302 305 s = ctx.description()
303 306 if isinstance(s, encoding.localstr):
304 307 # try hard to preserve utf-8 bytes
305 308 return encoding.tolocal(encoding.fromlocal(s).strip())
306 309 else:
307 310 return s.strip()
308 311
309 312 @templatekeyword('diffstat')
310 313 def showdiffstat(repo, ctx, templ, **args):
311 314 """String. Statistics of changes with the following format:
312 315 "modified files: +added/-removed lines"
313 316 """
314 317 stats = patch.diffstatdata(util.iterlines(ctx.diff(noprefix=False)))
315 318 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
316 319 return '%s: +%s/-%s' % (len(stats), adds, removes)
317 320
318 321 @templatekeyword('envvars')
319 322 def showenvvars(repo, **args):
320 323 """A dictionary of environment variables. (EXPERIMENTAL)"""
321 324
322 325 env = repo.ui.exportableenviron()
323 326 env = util.sortdict((k, env[k]) for k in sorted(env))
324 327 makemap = lambda k: {'key': k, 'value': env[k]}
325 328 c = [makemap(k) for k in env]
326 329 f = _showlist('envvar', c, plural='envvars', **args)
327 330 return _hybrid(f, env, makemap,
328 331 lambda x: '%s=%s' % (x['key'], x['value']))
329 332
330 333 @templatekeyword('extras')
331 334 def showextras(**args):
332 335 """List of dicts with key, value entries of the 'extras'
333 336 field of this changeset."""
334 337 extras = args['ctx'].extra()
335 338 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
336 339 makemap = lambda k: {'key': k, 'value': extras[k]}
337 340 c = [makemap(k) for k in extras]
338 341 f = _showlist('extra', c, plural='extras', **args)
339 342 return _hybrid(f, extras, makemap,
340 343 lambda x: '%s=%s' % (x['key'], util.escapestr(x['value'])))
341 344
342 345 @templatekeyword('file_adds')
343 346 def showfileadds(**args):
344 347 """List of strings. Files added by this changeset."""
345 348 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
346 349 return showlist('file_add', getfiles(repo, ctx, revcache)[1],
347 350 element='file', **args)
348 351
349 352 @templatekeyword('file_copies')
350 353 def showfilecopies(**args):
351 354 """List of strings. Files copied in this changeset with
352 355 their sources.
353 356 """
354 357 cache, ctx = args['cache'], args['ctx']
355 358 copies = args['revcache'].get('copies')
356 359 if copies is None:
357 360 if 'getrenamed' not in cache:
358 361 cache['getrenamed'] = getrenamedfn(args['repo'])
359 362 copies = []
360 363 getrenamed = cache['getrenamed']
361 364 for fn in ctx.files():
362 365 rename = getrenamed(fn, ctx.rev())
363 366 if rename:
364 367 copies.append((fn, rename[0]))
365 368
366 369 copies = util.sortdict(copies)
367 370 makemap = lambda k: {'name': k, 'source': copies[k]}
368 371 c = [makemap(k) for k in copies]
369 372 f = _showlist('file_copy', c, plural='file_copies', **args)
370 373 return _hybrid(f, copies, makemap,
371 374 lambda x: '%s (%s)' % (x['name'], x['source']))
372 375
373 376 # showfilecopiesswitch() displays file copies only if copy records are
374 377 # provided before calling the templater, usually with a --copies
375 378 # command line switch.
376 379 @templatekeyword('file_copies_switch')
377 380 def showfilecopiesswitch(**args):
378 381 """List of strings. Like "file_copies" but displayed
379 382 only if the --copied switch is set.
380 383 """
381 384 copies = args['revcache'].get('copies') or []
382 385 copies = util.sortdict(copies)
383 386 makemap = lambda k: {'name': k, 'source': copies[k]}
384 387 c = [makemap(k) for k in copies]
385 388 f = _showlist('file_copy', c, plural='file_copies', **args)
386 389 return _hybrid(f, copies, makemap,
387 390 lambda x: '%s (%s)' % (x['name'], x['source']))
388 391
389 392 @templatekeyword('file_dels')
390 393 def showfiledels(**args):
391 394 """List of strings. Files removed by this changeset."""
392 395 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
393 396 return showlist('file_del', getfiles(repo, ctx, revcache)[2],
394 397 element='file', **args)
395 398
396 399 @templatekeyword('file_mods')
397 400 def showfilemods(**args):
398 401 """List of strings. Files modified by this changeset."""
399 402 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
400 403 return showlist('file_mod', getfiles(repo, ctx, revcache)[0],
401 404 element='file', **args)
402 405
403 406 @templatekeyword('files')
404 407 def showfiles(**args):
405 408 """List of strings. All files modified, added, or removed by this
406 409 changeset.
407 410 """
408 411 return showlist('file', args['ctx'].files(), **args)
409 412
410 413 @templatekeyword('graphnode')
411 414 def showgraphnode(repo, ctx, **args):
412 415 """String. The character representing the changeset node in
413 416 an ASCII revision graph"""
414 417 wpnodes = repo.dirstate.parents()
415 418 if wpnodes[1] == nullid:
416 419 wpnodes = wpnodes[:1]
417 420 if ctx.node() in wpnodes:
418 421 return '@'
419 422 elif ctx.obsolete():
420 423 return 'x'
421 424 elif ctx.closesbranch():
422 425 return '_'
423 426 else:
424 427 return 'o'
425 428
426 429 @templatekeyword('index')
427 430 def showindex(**args):
428 431 """Integer. The current iteration of the loop. (0 indexed)"""
429 432 # just hosts documentation; should be overridden by template mapping
430 433 raise error.Abort(_("can't use index in this context"))
431 434
432 435 @templatekeyword('latesttag')
433 436 def showlatesttag(**args):
434 437 """List of strings. The global tags on the most recent globally
435 438 tagged ancestor of this changeset. If no such tags exist, the list
436 439 consists of the single string "null".
437 440 """
438 441 return showlatesttags(None, **args)
439 442
440 443 def showlatesttags(pattern, **args):
441 444 """helper method for the latesttag keyword and function"""
442 445 repo, ctx = args['repo'], args['ctx']
443 446 cache = args['cache']
444 447 latesttags = getlatesttags(repo, ctx, cache, pattern)
445 448
446 449 # latesttag[0] is an implementation detail for sorting csets on different
447 450 # branches in a stable manner- it is the date the tagged cset was created,
448 451 # not the date the tag was created. Therefore it isn't made visible here.
449 452 makemap = lambda v: {
450 453 'changes': _showchangessincetag,
451 454 'distance': latesttags[1],
452 455 'latesttag': v, # BC with {latesttag % '{latesttag}'}
453 456 'tag': v
454 457 }
455 458
456 459 tags = latesttags[2]
457 460 f = _showlist('latesttag', tags, separator=':', **args)
458 461 return _hybrid(f, tags, makemap, lambda x: x['latesttag'])
459 462
460 463 @templatekeyword('latesttagdistance')
461 464 def showlatesttagdistance(repo, ctx, templ, cache, **args):
462 465 """Integer. Longest path to the latest tag."""
463 466 return getlatesttags(repo, ctx, cache)[1]
464 467
465 468 @templatekeyword('changessincelatesttag')
466 469 def showchangessincelatesttag(repo, ctx, templ, cache, **args):
467 470 """Integer. All ancestors not in the latest tag."""
468 471 latesttag = getlatesttags(repo, ctx, cache)[2][0]
469 472
470 473 return _showchangessincetag(repo, ctx, tag=latesttag, **args)
471 474
472 475 def _showchangessincetag(repo, ctx, **args):
473 476 offset = 0
474 477 revs = [ctx.rev()]
475 478 tag = args['tag']
476 479
477 480 # The only() revset doesn't currently support wdir()
478 481 if ctx.rev() is None:
479 482 offset = 1
480 483 revs = [p.rev() for p in ctx.parents()]
481 484
482 485 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
483 486
484 487 @templatekeyword('manifest')
485 488 def showmanifest(**args):
486 489 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
487 490 mnode = ctx.manifestnode()
488 491 if mnode is None:
489 492 # just avoid crash, we might want to use the 'ff...' hash in future
490 493 return
491 494 args = args.copy()
492 495 args.update({'rev': repo.manifestlog._revlog.rev(mnode),
493 496 'node': hex(mnode)})
494 497 return templ('manifest', **args)
495 498
496 499 def shownames(namespace, **args):
497 500 """helper method to generate a template keyword for a namespace"""
498 501 ctx = args['ctx']
499 502 repo = ctx.repo()
500 503 ns = repo.names[namespace]
501 504 names = ns.names(repo, ctx.node())
502 505 return showlist(ns.templatename, names, plural=namespace, **args)
503 506
504 507 @templatekeyword('namespaces')
505 508 def shownamespaces(**args):
506 509 """Dict of lists. Names attached to this changeset per
507 510 namespace."""
508 511 ctx = args['ctx']
509 512 repo = ctx.repo()
510 513 namespaces = util.sortdict((k, showlist('name', ns.names(repo, ctx.node()),
511 514 **args))
512 515 for k, ns in repo.names.iteritems())
513 516 f = _showlist('namespace', list(namespaces), **args)
514 517 return _hybrid(f, namespaces,
515 518 lambda k: {'namespace': k, 'names': namespaces[k]},
516 519 lambda x: x['namespace'])
517 520
518 521 @templatekeyword('node')
519 522 def shownode(repo, ctx, templ, **args):
520 523 """String. The changeset identification hash, as a 40 hexadecimal
521 524 digit string.
522 525 """
523 526 return ctx.hex()
524 527
525 528 @templatekeyword('obsolete')
526 529 def showobsolete(repo, ctx, templ, **args):
527 530 """String. Whether the changeset is obsolete.
528 531 """
529 532 if ctx.obsolete():
530 533 return 'obsolete'
531 534 return ''
532 535
533 536 @templatekeyword('p1rev')
534 537 def showp1rev(repo, ctx, templ, **args):
535 538 """Integer. The repository-local revision number of the changeset's
536 539 first parent, or -1 if the changeset has no parents."""
537 540 return ctx.p1().rev()
538 541
539 542 @templatekeyword('p2rev')
540 543 def showp2rev(repo, ctx, templ, **args):
541 544 """Integer. The repository-local revision number of the changeset's
542 545 second parent, or -1 if the changeset has no second parent."""
543 546 return ctx.p2().rev()
544 547
545 548 @templatekeyword('p1node')
546 549 def showp1node(repo, ctx, templ, **args):
547 550 """String. The identification hash of the changeset's first parent,
548 551 as a 40 digit hexadecimal string. If the changeset has no parents, all
549 552 digits are 0."""
550 553 return ctx.p1().hex()
551 554
552 555 @templatekeyword('p2node')
553 556 def showp2node(repo, ctx, templ, **args):
554 557 """String. The identification hash of the changeset's second
555 558 parent, as a 40 digit hexadecimal string. If the changeset has no second
556 559 parent, all digits are 0."""
557 560 return ctx.p2().hex()
558 561
559 562 @templatekeyword('parents')
560 563 def showparents(**args):
561 564 """List of strings. The parents of the changeset in "rev:node"
562 565 format. If the changeset has only one "natural" parent (the predecessor
563 566 revision) nothing is shown."""
564 567 repo = args['repo']
565 568 ctx = args['ctx']
566 569 pctxs = scmutil.meaningfulparents(repo, ctx)
567 570 prevs = [str(p.rev()) for p in pctxs] # ifcontains() needs a list of str
568 571 parents = [[('rev', p.rev()),
569 572 ('node', p.hex()),
570 573 ('phase', p.phasestr())]
571 574 for p in pctxs]
572 575 f = _showlist('parent', parents, **args)
573 576 return _hybrid(f, prevs, lambda x: {'ctx': repo[int(x)], 'revcache': {}},
574 577 lambda d: _formatrevnode(d['ctx']))
575 578
576 579 @templatekeyword('phase')
577 580 def showphase(repo, ctx, templ, **args):
578 581 """String. The changeset phase name."""
579 582 return ctx.phasestr()
580 583
581 584 @templatekeyword('phaseidx')
582 585 def showphaseidx(repo, ctx, templ, **args):
583 586 """Integer. The changeset phase index."""
584 587 return ctx.phase()
585 588
586 589 @templatekeyword('rev')
587 590 def showrev(repo, ctx, templ, **args):
588 591 """Integer. The repository-local changeset revision number."""
589 592 return scmutil.intrev(ctx.rev())
590 593
591 594 def showrevslist(name, revs, **args):
592 595 """helper to generate a list of revisions in which a mapped template will
593 596 be evaluated"""
594 597 repo = args['ctx'].repo()
595 598 revs = [str(r) for r in revs] # ifcontains() needs a list of str
596 599 f = _showlist(name, revs, **args)
597 600 return _hybrid(f, revs,
598 601 lambda x: {name: x, 'ctx': repo[int(x)], 'revcache': {}},
599 602 lambda d: d[name])
600 603
601 604 @templatekeyword('subrepos')
602 605 def showsubrepos(**args):
603 606 """List of strings. Updated subrepositories in the changeset."""
604 607 ctx = args['ctx']
605 608 substate = ctx.substate
606 609 if not substate:
607 610 return showlist('subrepo', [], **args)
608 611 psubstate = ctx.parents()[0].substate or {}
609 612 subrepos = []
610 613 for sub in substate:
611 614 if sub not in psubstate or substate[sub] != psubstate[sub]:
612 615 subrepos.append(sub) # modified or newly added in ctx
613 616 for sub in psubstate:
614 617 if sub not in substate:
615 618 subrepos.append(sub) # removed in ctx
616 619 return showlist('subrepo', sorted(subrepos), **args)
617 620
618 621 # don't remove "showtags" definition, even though namespaces will put
619 622 # a helper function for "tags" keyword into "keywords" map automatically,
620 623 # because online help text is built without namespaces initialization
621 624 @templatekeyword('tags')
622 625 def showtags(**args):
623 626 """List of strings. Any tags associated with the changeset."""
624 627 return shownames('tags', **args)
625 628
626 629 def loadkeyword(ui, extname, registrarobj):
627 630 """Load template keyword from specified registrarobj
628 631 """
629 632 for name, func in registrarobj._table.iteritems():
630 633 keywords[name] = func
631 634
632 635 @templatekeyword('termwidth')
633 636 def termwidth(repo, ctx, templ, **args):
634 637 """Integer. The width of the current terminal."""
635 638 return repo.ui.termwidth()
636 639
637 640 @templatekeyword('troubles')
638 641 def showtroubles(**args):
639 642 """List of strings. Evolution troubles affecting the changeset.
640 643
641 644 (EXPERIMENTAL)
642 645 """
643 646 return showlist('trouble', args['ctx'].troubles(), **args)
644 647
645 648 # tell hggettext to extract docstrings from these functions:
646 649 i18nfunctions = keywords.values()
General Comments 0
You need to be logged in to leave comments. Login now