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