##// END OF EJS Templates
templatekw: add {size} keyword as an example of fctx-based keyword...
Yuya Nishihara -
r39623:918944f5 default
parent child Browse files
Show More
@@ -1,821 +1,827 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 (
12 12 hex,
13 13 nullid,
14 14 )
15 15
16 16 from . import (
17 17 diffutil,
18 18 encoding,
19 19 error,
20 20 hbisect,
21 21 i18n,
22 22 obsutil,
23 23 patch,
24 24 pycompat,
25 25 registrar,
26 26 scmutil,
27 27 templateutil,
28 28 util,
29 29 )
30 30 from .utils import (
31 31 stringutil,
32 32 )
33 33
34 34 _hybrid = templateutil.hybrid
35 35 hybriddict = templateutil.hybriddict
36 36 hybridlist = templateutil.hybridlist
37 37 compatdict = templateutil.compatdict
38 38 compatlist = templateutil.compatlist
39 39 _showcompatlist = templateutil._showcompatlist
40 40
41 41 def getlatesttags(context, mapping, pattern=None):
42 42 '''return date, distance and name for the latest tag of rev'''
43 43 repo = context.resource(mapping, 'repo')
44 44 ctx = context.resource(mapping, 'ctx')
45 45 cache = context.resource(mapping, 'cache')
46 46
47 47 cachename = 'latesttags'
48 48 if pattern is not None:
49 49 cachename += '-' + pattern
50 50 match = stringutil.stringmatcher(pattern)[2]
51 51 else:
52 52 match = util.always
53 53
54 54 if cachename not in cache:
55 55 # Cache mapping from rev to a tuple with tag date, tag
56 56 # distance and tag name
57 57 cache[cachename] = {-1: (0, 0, ['null'])}
58 58 latesttags = cache[cachename]
59 59
60 60 rev = ctx.rev()
61 61 todo = [rev]
62 62 while todo:
63 63 rev = todo.pop()
64 64 if rev in latesttags:
65 65 continue
66 66 ctx = repo[rev]
67 67 tags = [t for t in ctx.tags()
68 68 if (repo.tagtype(t) and repo.tagtype(t) != 'local'
69 69 and match(t))]
70 70 if tags:
71 71 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
72 72 continue
73 73 try:
74 74 ptags = [latesttags[p.rev()] for p in ctx.parents()]
75 75 if len(ptags) > 1:
76 76 if ptags[0][2] == ptags[1][2]:
77 77 # The tuples are laid out so the right one can be found by
78 78 # comparison in this case.
79 79 pdate, pdist, ptag = max(ptags)
80 80 else:
81 81 def key(x):
82 82 changessincetag = len(repo.revs('only(%d, %s)',
83 83 ctx.rev(), x[2][0]))
84 84 # Smallest number of changes since tag wins. Date is
85 85 # used as tiebreaker.
86 86 return [-changessincetag, x[0]]
87 87 pdate, pdist, ptag = max(ptags, key=key)
88 88 else:
89 89 pdate, pdist, ptag = ptags[0]
90 90 except KeyError:
91 91 # Cache miss - recurse
92 92 todo.append(rev)
93 93 todo.extend(p.rev() for p in ctx.parents())
94 94 continue
95 95 latesttags[rev] = pdate, pdist + 1, ptag
96 96 return latesttags[rev]
97 97
98 98 def getrenamedfn(repo, endrev=None):
99 99 rcache = {}
100 100 if endrev is None:
101 101 endrev = len(repo)
102 102
103 103 def getrenamed(fn, rev):
104 104 '''looks up all renames for a file (up to endrev) the first
105 105 time the file is given. It indexes on the changerev and only
106 106 parses the manifest if linkrev != changerev.
107 107 Returns rename info for fn at changerev rev.'''
108 108 if fn not in rcache:
109 109 rcache[fn] = {}
110 110 fl = repo.file(fn)
111 111 for i in fl:
112 112 lr = fl.linkrev(i)
113 113 renamed = fl.renamed(fl.node(i))
114 114 rcache[fn][lr] = renamed and renamed[0]
115 115 if lr >= endrev:
116 116 break
117 117 if rev in rcache[fn]:
118 118 return rcache[fn][rev]
119 119
120 120 # If linkrev != rev (i.e. rev not found in rcache) fallback to
121 121 # filectx logic.
122 122 try:
123 123 renamed = repo[rev][fn].renamed()
124 124 return renamed and renamed[0]
125 125 except error.LookupError:
126 126 return None
127 127
128 128 return getrenamed
129 129
130 130 def getlogcolumns():
131 131 """Return a dict of log column labels"""
132 132 _ = pycompat.identity # temporarily disable gettext
133 133 # i18n: column positioning for "hg log"
134 134 columns = _('bookmark: %s\n'
135 135 'branch: %s\n'
136 136 'changeset: %s\n'
137 137 'copies: %s\n'
138 138 'date: %s\n'
139 139 'extra: %s=%s\n'
140 140 'files+: %s\n'
141 141 'files-: %s\n'
142 142 'files: %s\n'
143 143 'instability: %s\n'
144 144 'manifest: %s\n'
145 145 'obsolete: %s\n'
146 146 'parent: %s\n'
147 147 'phase: %s\n'
148 148 'summary: %s\n'
149 149 'tag: %s\n'
150 150 'user: %s\n')
151 151 return dict(zip([s.split(':', 1)[0] for s in columns.splitlines()],
152 152 i18n._(columns).splitlines(True)))
153 153
154 154 # default templates internally used for rendering of lists
155 155 defaulttempl = {
156 156 'parent': '{rev}:{node|formatnode} ',
157 157 'manifest': '{rev}:{node|formatnode}',
158 158 'file_copy': '{name} ({source})',
159 159 'envvar': '{key}={value}',
160 160 'extra': '{key}={value|stringescape}'
161 161 }
162 162 # filecopy is preserved for compatibility reasons
163 163 defaulttempl['filecopy'] = defaulttempl['file_copy']
164 164
165 165 # keywords are callables (see registrar.templatekeyword for details)
166 166 keywords = {}
167 167 templatekeyword = registrar.templatekeyword(keywords)
168 168
169 169 @templatekeyword('author', requires={'ctx'})
170 170 def showauthor(context, mapping):
171 171 """Alias for ``{user}``"""
172 172 return showuser(context, mapping)
173 173
174 174 @templatekeyword('bisect', requires={'repo', 'ctx'})
175 175 def showbisect(context, mapping):
176 176 """String. The changeset bisection status."""
177 177 repo = context.resource(mapping, 'repo')
178 178 ctx = context.resource(mapping, 'ctx')
179 179 return hbisect.label(repo, ctx.node())
180 180
181 181 @templatekeyword('branch', requires={'ctx'})
182 182 def showbranch(context, mapping):
183 183 """String. The name of the branch on which the changeset was
184 184 committed.
185 185 """
186 186 ctx = context.resource(mapping, 'ctx')
187 187 return ctx.branch()
188 188
189 189 @templatekeyword('branches', requires={'ctx'})
190 190 def showbranches(context, mapping):
191 191 """List of strings. The name of the branch on which the
192 192 changeset was committed. Will be empty if the branch name was
193 193 default. (DEPRECATED)
194 194 """
195 195 ctx = context.resource(mapping, 'ctx')
196 196 branch = ctx.branch()
197 197 if branch != 'default':
198 198 return compatlist(context, mapping, 'branch', [branch],
199 199 plural='branches')
200 200 return compatlist(context, mapping, 'branch', [], plural='branches')
201 201
202 202 @templatekeyword('bookmarks', requires={'repo', 'ctx'})
203 203 def showbookmarks(context, mapping):
204 204 """List of strings. Any bookmarks associated with the
205 205 changeset. Also sets 'active', the name of the active bookmark.
206 206 """
207 207 repo = context.resource(mapping, 'repo')
208 208 ctx = context.resource(mapping, 'ctx')
209 209 bookmarks = ctx.bookmarks()
210 210 active = repo._activebookmark
211 211 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
212 212 f = _showcompatlist(context, mapping, 'bookmark', bookmarks)
213 213 return _hybrid(f, bookmarks, makemap, pycompat.identity)
214 214
215 215 @templatekeyword('children', requires={'ctx'})
216 216 def showchildren(context, mapping):
217 217 """List of strings. The children of the changeset."""
218 218 ctx = context.resource(mapping, 'ctx')
219 219 childrevs = ['%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
220 220 return compatlist(context, mapping, 'children', childrevs, element='child')
221 221
222 222 # Deprecated, but kept alive for help generation a purpose.
223 223 @templatekeyword('currentbookmark', requires={'repo', 'ctx'})
224 224 def showcurrentbookmark(context, mapping):
225 225 """String. The active bookmark, if it is associated with the changeset.
226 226 (DEPRECATED)"""
227 227 return showactivebookmark(context, mapping)
228 228
229 229 @templatekeyword('activebookmark', requires={'repo', 'ctx'})
230 230 def showactivebookmark(context, mapping):
231 231 """String. The active bookmark, if it is associated with the changeset."""
232 232 repo = context.resource(mapping, 'repo')
233 233 ctx = context.resource(mapping, 'ctx')
234 234 active = repo._activebookmark
235 235 if active and active in ctx.bookmarks():
236 236 return active
237 237 return ''
238 238
239 239 @templatekeyword('date', requires={'ctx'})
240 240 def showdate(context, mapping):
241 241 """Date information. The date when the changeset was committed."""
242 242 ctx = context.resource(mapping, 'ctx')
243 243 # the default string format is '<float(unixtime)><tzoffset>' because
244 244 # python-hglib splits date at decimal separator.
245 245 return templateutil.date(ctx.date(), showfmt='%d.0%d')
246 246
247 247 @templatekeyword('desc', requires={'ctx'})
248 248 def showdescription(context, mapping):
249 249 """String. The text of the changeset description."""
250 250 ctx = context.resource(mapping, 'ctx')
251 251 s = ctx.description()
252 252 if isinstance(s, encoding.localstr):
253 253 # try hard to preserve utf-8 bytes
254 254 return encoding.tolocal(encoding.fromlocal(s).strip())
255 255 elif isinstance(s, encoding.safelocalstr):
256 256 return encoding.safelocalstr(s.strip())
257 257 else:
258 258 return s.strip()
259 259
260 260 @templatekeyword('diffstat', requires={'ui', 'ctx'})
261 261 def showdiffstat(context, mapping):
262 262 """String. Statistics of changes with the following format:
263 263 "modified files: +added/-removed lines"
264 264 """
265 265 ui = context.resource(mapping, 'ui')
266 266 ctx = context.resource(mapping, 'ctx')
267 267 diffopts = diffutil.diffallopts(ui, {'noprefix': False})
268 268 diff = ctx.diff(opts=diffopts)
269 269 stats = patch.diffstatdata(util.iterlines(diff))
270 270 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
271 271 return '%d: +%d/-%d' % (len(stats), adds, removes)
272 272
273 273 @templatekeyword('envvars', requires={'ui'})
274 274 def showenvvars(context, mapping):
275 275 """A dictionary of environment variables. (EXPERIMENTAL)"""
276 276 ui = context.resource(mapping, 'ui')
277 277 env = ui.exportableenviron()
278 278 env = util.sortdict((k, env[k]) for k in sorted(env))
279 279 return compatdict(context, mapping, 'envvar', env, plural='envvars')
280 280
281 281 @templatekeyword('extras', requires={'ctx'})
282 282 def showextras(context, mapping):
283 283 """List of dicts with key, value entries of the 'extras'
284 284 field of this changeset."""
285 285 ctx = context.resource(mapping, 'ctx')
286 286 extras = ctx.extra()
287 287 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
288 288 makemap = lambda k: {'key': k, 'value': extras[k]}
289 289 c = [makemap(k) for k in extras]
290 290 f = _showcompatlist(context, mapping, 'extra', c, plural='extras')
291 291 return _hybrid(f, extras, makemap,
292 292 lambda k: '%s=%s' % (k, stringutil.escapestr(extras[k])))
293 293
294 294 def _showfilesbystat(context, mapping, name, index):
295 295 ctx = context.resource(mapping, 'ctx')
296 296 revcache = context.resource(mapping, 'revcache')
297 297 if 'files' not in revcache:
298 298 revcache['files'] = ctx.p1().status(ctx)[:3]
299 299 files = revcache['files'][index]
300 300 return templateutil.compatfileslist(context, mapping, name, files)
301 301
302 302 @templatekeyword('file_adds', requires={'ctx', 'revcache'})
303 303 def showfileadds(context, mapping):
304 304 """List of strings. Files added by this changeset."""
305 305 return _showfilesbystat(context, mapping, 'file_add', 1)
306 306
307 307 @templatekeyword('file_copies',
308 308 requires={'repo', 'ctx', 'cache', 'revcache'})
309 309 def showfilecopies(context, mapping):
310 310 """List of strings. Files copied in this changeset with
311 311 their sources.
312 312 """
313 313 repo = context.resource(mapping, 'repo')
314 314 ctx = context.resource(mapping, 'ctx')
315 315 cache = context.resource(mapping, 'cache')
316 316 copies = context.resource(mapping, 'revcache').get('copies')
317 317 if copies is None:
318 318 if 'getrenamed' not in cache:
319 319 cache['getrenamed'] = getrenamedfn(repo)
320 320 copies = []
321 321 getrenamed = cache['getrenamed']
322 322 for fn in ctx.files():
323 323 rename = getrenamed(fn, ctx.rev())
324 324 if rename:
325 325 copies.append((fn, rename))
326 326 return templateutil.compatfilecopiesdict(context, mapping, 'file_copy',
327 327 copies)
328 328
329 329 # showfilecopiesswitch() displays file copies only if copy records are
330 330 # provided before calling the templater, usually with a --copies
331 331 # command line switch.
332 332 @templatekeyword('file_copies_switch', requires={'revcache'})
333 333 def showfilecopiesswitch(context, mapping):
334 334 """List of strings. Like "file_copies" but displayed
335 335 only if the --copied switch is set.
336 336 """
337 337 copies = context.resource(mapping, 'revcache').get('copies') or []
338 338 return templateutil.compatfilecopiesdict(context, mapping, 'file_copy',
339 339 copies)
340 340
341 341 @templatekeyword('file_dels', requires={'ctx', 'revcache'})
342 342 def showfiledels(context, mapping):
343 343 """List of strings. Files removed by this changeset."""
344 344 return _showfilesbystat(context, mapping, 'file_del', 2)
345 345
346 346 @templatekeyword('file_mods', requires={'ctx', 'revcache'})
347 347 def showfilemods(context, mapping):
348 348 """List of strings. Files modified by this changeset."""
349 349 return _showfilesbystat(context, mapping, 'file_mod', 0)
350 350
351 351 @templatekeyword('files', requires={'ctx'})
352 352 def showfiles(context, mapping):
353 353 """List of strings. All files modified, added, or removed by this
354 354 changeset.
355 355 """
356 356 ctx = context.resource(mapping, 'ctx')
357 357 return templateutil.compatfileslist(context, mapping, 'file', ctx.files())
358 358
359 359 @templatekeyword('graphnode', requires={'repo', 'ctx'})
360 360 def showgraphnode(context, mapping):
361 361 """String. The character representing the changeset node in an ASCII
362 362 revision graph."""
363 363 repo = context.resource(mapping, 'repo')
364 364 ctx = context.resource(mapping, 'ctx')
365 365 return getgraphnode(repo, ctx)
366 366
367 367 def getgraphnode(repo, ctx):
368 368 return getgraphnodecurrent(repo, ctx) or getgraphnodesymbol(ctx)
369 369
370 370 def getgraphnodecurrent(repo, ctx):
371 371 wpnodes = repo.dirstate.parents()
372 372 if wpnodes[1] == nullid:
373 373 wpnodes = wpnodes[:1]
374 374 if ctx.node() in wpnodes:
375 375 return '@'
376 376 else:
377 377 return ''
378 378
379 379 def getgraphnodesymbol(ctx):
380 380 if ctx.obsolete():
381 381 return 'x'
382 382 elif ctx.isunstable():
383 383 return '*'
384 384 elif ctx.closesbranch():
385 385 return '_'
386 386 else:
387 387 return 'o'
388 388
389 389 @templatekeyword('graphwidth', requires=())
390 390 def showgraphwidth(context, mapping):
391 391 """Integer. The width of the graph drawn by 'log --graph' or zero."""
392 392 # just hosts documentation; should be overridden by template mapping
393 393 return 0
394 394
395 395 @templatekeyword('index', requires=())
396 396 def showindex(context, mapping):
397 397 """Integer. The current iteration of the loop. (0 indexed)"""
398 398 # just hosts documentation; should be overridden by template mapping
399 399 raise error.Abort(_("can't use index in this context"))
400 400
401 401 @templatekeyword('latesttag', requires={'repo', 'ctx', 'cache'})
402 402 def showlatesttag(context, mapping):
403 403 """List of strings. The global tags on the most recent globally
404 404 tagged ancestor of this changeset. If no such tags exist, the list
405 405 consists of the single string "null".
406 406 """
407 407 return showlatesttags(context, mapping, None)
408 408
409 409 def showlatesttags(context, mapping, pattern):
410 410 """helper method for the latesttag keyword and function"""
411 411 latesttags = getlatesttags(context, mapping, pattern)
412 412
413 413 # latesttag[0] is an implementation detail for sorting csets on different
414 414 # branches in a stable manner- it is the date the tagged cset was created,
415 415 # not the date the tag was created. Therefore it isn't made visible here.
416 416 makemap = lambda v: {
417 417 'changes': _showchangessincetag,
418 418 'distance': latesttags[1],
419 419 'latesttag': v, # BC with {latesttag % '{latesttag}'}
420 420 'tag': v
421 421 }
422 422
423 423 tags = latesttags[2]
424 424 f = _showcompatlist(context, mapping, 'latesttag', tags, separator=':')
425 425 return _hybrid(f, tags, makemap, pycompat.identity)
426 426
427 427 @templatekeyword('latesttagdistance', requires={'repo', 'ctx', 'cache'})
428 428 def showlatesttagdistance(context, mapping):
429 429 """Integer. Longest path to the latest tag."""
430 430 return getlatesttags(context, mapping)[1]
431 431
432 432 @templatekeyword('changessincelatesttag', requires={'repo', 'ctx', 'cache'})
433 433 def showchangessincelatesttag(context, mapping):
434 434 """Integer. All ancestors not in the latest tag."""
435 435 tag = getlatesttags(context, mapping)[2][0]
436 436 mapping = context.overlaymap(mapping, {'tag': tag})
437 437 return _showchangessincetag(context, mapping)
438 438
439 439 def _showchangessincetag(context, mapping):
440 440 repo = context.resource(mapping, 'repo')
441 441 ctx = context.resource(mapping, 'ctx')
442 442 offset = 0
443 443 revs = [ctx.rev()]
444 444 tag = context.symbol(mapping, 'tag')
445 445
446 446 # The only() revset doesn't currently support wdir()
447 447 if ctx.rev() is None:
448 448 offset = 1
449 449 revs = [p.rev() for p in ctx.parents()]
450 450
451 451 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
452 452
453 453 # teach templater latesttags.changes is switched to (context, mapping) API
454 454 _showchangessincetag._requires = {'repo', 'ctx'}
455 455
456 456 @templatekeyword('manifest', requires={'repo', 'ctx'})
457 457 def showmanifest(context, mapping):
458 458 repo = context.resource(mapping, 'repo')
459 459 ctx = context.resource(mapping, 'ctx')
460 460 mnode = ctx.manifestnode()
461 461 if mnode is None:
462 462 # just avoid crash, we might want to use the 'ff...' hash in future
463 463 return
464 464 mrev = repo.manifestlog.rev(mnode)
465 465 mhex = hex(mnode)
466 466 mapping = context.overlaymap(mapping, {'rev': mrev, 'node': mhex})
467 467 f = context.process('manifest', mapping)
468 468 # TODO: perhaps 'ctx' should be dropped from mapping because manifest
469 469 # rev and node are completely different from changeset's.
470 470 return templateutil.hybriditem(f, None, f,
471 471 lambda x: {'rev': mrev, 'node': mhex})
472 472
473 473 @templatekeyword('obsfate', requires={'ui', 'repo', 'ctx'})
474 474 def showobsfate(context, mapping):
475 475 # this function returns a list containing pre-formatted obsfate strings.
476 476 #
477 477 # This function will be replaced by templates fragments when we will have
478 478 # the verbosity templatekw available.
479 479 succsandmarkers = showsuccsandmarkers(context, mapping)
480 480
481 481 ui = context.resource(mapping, 'ui')
482 482 repo = context.resource(mapping, 'repo')
483 483 values = []
484 484
485 485 for x in succsandmarkers.tovalue(context, mapping):
486 486 v = obsutil.obsfateprinter(ui, repo, x['successors'], x['markers'],
487 487 scmutil.formatchangeid)
488 488 values.append(v)
489 489
490 490 return compatlist(context, mapping, "fate", values)
491 491
492 492 def shownames(context, mapping, namespace):
493 493 """helper method to generate a template keyword for a namespace"""
494 494 repo = context.resource(mapping, 'repo')
495 495 ctx = context.resource(mapping, 'ctx')
496 496 ns = repo.names[namespace]
497 497 names = ns.names(repo, ctx.node())
498 498 return compatlist(context, mapping, ns.templatename, names,
499 499 plural=namespace)
500 500
501 501 @templatekeyword('namespaces', requires={'repo', 'ctx'})
502 502 def shownamespaces(context, mapping):
503 503 """Dict of lists. Names attached to this changeset per
504 504 namespace."""
505 505 repo = context.resource(mapping, 'repo')
506 506 ctx = context.resource(mapping, 'ctx')
507 507
508 508 namespaces = util.sortdict()
509 509 def makensmapfn(ns):
510 510 # 'name' for iterating over namespaces, templatename for local reference
511 511 return lambda v: {'name': v, ns.templatename: v}
512 512
513 513 for k, ns in repo.names.iteritems():
514 514 names = ns.names(repo, ctx.node())
515 515 f = _showcompatlist(context, mapping, 'name', names)
516 516 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
517 517
518 518 f = _showcompatlist(context, mapping, 'namespace', list(namespaces))
519 519
520 520 def makemap(ns):
521 521 return {
522 522 'namespace': ns,
523 523 'names': namespaces[ns],
524 524 'builtin': repo.names[ns].builtin,
525 525 'colorname': repo.names[ns].colorname,
526 526 }
527 527
528 528 return _hybrid(f, namespaces, makemap, pycompat.identity)
529 529
530 530 @templatekeyword('node', requires={'ctx'})
531 531 def shownode(context, mapping):
532 532 """String. The changeset identification hash, as a 40 hexadecimal
533 533 digit string.
534 534 """
535 535 ctx = context.resource(mapping, 'ctx')
536 536 return ctx.hex()
537 537
538 538 @templatekeyword('obsolete', requires={'ctx'})
539 539 def showobsolete(context, mapping):
540 540 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
541 541 ctx = context.resource(mapping, 'ctx')
542 542 if ctx.obsolete():
543 543 return 'obsolete'
544 544 return ''
545 545
546 546 @templatekeyword('path', requires={'fctx'})
547 547 def showpath(context, mapping):
548 548 """String. Repository-absolute path of the current file. (EXPERIMENTAL)"""
549 549 fctx = context.resource(mapping, 'fctx')
550 550 return fctx.path()
551 551
552 552 @templatekeyword('peerurls', requires={'repo'})
553 553 def showpeerurls(context, mapping):
554 554 """A dictionary of repository locations defined in the [paths] section
555 555 of your configuration file."""
556 556 repo = context.resource(mapping, 'repo')
557 557 # see commands.paths() for naming of dictionary keys
558 558 paths = repo.ui.paths
559 559 urls = util.sortdict((k, p.rawloc) for k, p in sorted(paths.iteritems()))
560 560 def makemap(k):
561 561 p = paths[k]
562 562 d = {'name': k, 'url': p.rawloc}
563 563 d.update((o, v) for o, v in sorted(p.suboptions.iteritems()))
564 564 return d
565 565 return _hybrid(None, urls, makemap, lambda k: '%s=%s' % (k, urls[k]))
566 566
567 567 @templatekeyword("predecessors", requires={'repo', 'ctx'})
568 568 def showpredecessors(context, mapping):
569 569 """Returns the list if the closest visible successors. (EXPERIMENTAL)"""
570 570 repo = context.resource(mapping, 'repo')
571 571 ctx = context.resource(mapping, 'ctx')
572 572 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
573 573 predecessors = pycompat.maplist(hex, predecessors)
574 574
575 575 return _hybrid(None, predecessors,
576 576 lambda x: {'ctx': repo[x]},
577 577 lambda x: scmutil.formatchangeid(repo[x]))
578 578
579 579 @templatekeyword('reporoot', requires={'repo'})
580 580 def showreporoot(context, mapping):
581 581 """String. The root directory of the current repository."""
582 582 repo = context.resource(mapping, 'repo')
583 583 return repo.root
584 584
585 @templatekeyword('size', requires={'fctx'})
586 def showsize(context, mapping):
587 """Integer. Size of the current file in bytes. (EXPERIMENTAL)"""
588 fctx = context.resource(mapping, 'fctx')
589 return fctx.size()
590
585 591 @templatekeyword("successorssets", requires={'repo', 'ctx'})
586 592 def showsuccessorssets(context, mapping):
587 593 """Returns a string of sets of successors for a changectx. Format used
588 594 is: [ctx1, ctx2], [ctx3] if ctx has been splitted into ctx1 and ctx2
589 595 while also diverged into ctx3. (EXPERIMENTAL)"""
590 596 repo = context.resource(mapping, 'repo')
591 597 ctx = context.resource(mapping, 'ctx')
592 598 if not ctx.obsolete():
593 599 return ''
594 600
595 601 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
596 602 ssets = [[hex(n) for n in ss] for ss in ssets]
597 603
598 604 data = []
599 605 for ss in ssets:
600 606 h = _hybrid(None, ss, lambda x: {'ctx': repo[x]},
601 607 lambda x: scmutil.formatchangeid(repo[x]))
602 608 data.append(h)
603 609
604 610 # Format the successorssets
605 611 def render(d):
606 612 return templateutil.stringify(context, mapping, d)
607 613
608 614 def gen(data):
609 615 yield "; ".join(render(d) for d in data)
610 616
611 617 return _hybrid(gen(data), data, lambda x: {'successorset': x},
612 618 pycompat.identity)
613 619
614 620 @templatekeyword("succsandmarkers", requires={'repo', 'ctx'})
615 621 def showsuccsandmarkers(context, mapping):
616 622 """Returns a list of dict for each final successor of ctx. The dict
617 623 contains successors node id in "successors" keys and the list of
618 624 obs-markers from ctx to the set of successors in "markers".
619 625 (EXPERIMENTAL)
620 626 """
621 627 repo = context.resource(mapping, 'repo')
622 628 ctx = context.resource(mapping, 'ctx')
623 629
624 630 values = obsutil.successorsandmarkers(repo, ctx)
625 631
626 632 if values is None:
627 633 values = []
628 634
629 635 # Format successors and markers to avoid exposing binary to templates
630 636 data = []
631 637 for i in values:
632 638 # Format successors
633 639 successors = i['successors']
634 640
635 641 successors = [hex(n) for n in successors]
636 642 successors = _hybrid(None, successors,
637 643 lambda x: {'ctx': repo[x]},
638 644 lambda x: scmutil.formatchangeid(repo[x]))
639 645
640 646 # Format markers
641 647 finalmarkers = []
642 648 for m in i['markers']:
643 649 hexprec = hex(m[0])
644 650 hexsucs = tuple(hex(n) for n in m[1])
645 651 hexparents = None
646 652 if m[5] is not None:
647 653 hexparents = tuple(hex(n) for n in m[5])
648 654 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
649 655 finalmarkers.append(newmarker)
650 656
651 657 data.append({'successors': successors, 'markers': finalmarkers})
652 658
653 659 return templateutil.mappinglist(data)
654 660
655 661 @templatekeyword('p1rev', requires={'ctx'})
656 662 def showp1rev(context, mapping):
657 663 """Integer. The repository-local revision number of the changeset's
658 664 first parent, or -1 if the changeset has no parents."""
659 665 ctx = context.resource(mapping, 'ctx')
660 666 return ctx.p1().rev()
661 667
662 668 @templatekeyword('p2rev', requires={'ctx'})
663 669 def showp2rev(context, mapping):
664 670 """Integer. The repository-local revision number of the changeset's
665 671 second parent, or -1 if the changeset has no second parent."""
666 672 ctx = context.resource(mapping, 'ctx')
667 673 return ctx.p2().rev()
668 674
669 675 @templatekeyword('p1node', requires={'ctx'})
670 676 def showp1node(context, mapping):
671 677 """String. The identification hash of the changeset's first parent,
672 678 as a 40 digit hexadecimal string. If the changeset has no parents, all
673 679 digits are 0."""
674 680 ctx = context.resource(mapping, 'ctx')
675 681 return ctx.p1().hex()
676 682
677 683 @templatekeyword('p2node', requires={'ctx'})
678 684 def showp2node(context, mapping):
679 685 """String. The identification hash of the changeset's second
680 686 parent, as a 40 digit hexadecimal string. If the changeset has no second
681 687 parent, all digits are 0."""
682 688 ctx = context.resource(mapping, 'ctx')
683 689 return ctx.p2().hex()
684 690
685 691 @templatekeyword('parents', requires={'repo', 'ctx'})
686 692 def showparents(context, mapping):
687 693 """List of strings. The parents of the changeset in "rev:node"
688 694 format. If the changeset has only one "natural" parent (the predecessor
689 695 revision) nothing is shown."""
690 696 repo = context.resource(mapping, 'repo')
691 697 ctx = context.resource(mapping, 'ctx')
692 698 pctxs = scmutil.meaningfulparents(repo, ctx)
693 699 prevs = [p.rev() for p in pctxs]
694 700 parents = [[('rev', p.rev()),
695 701 ('node', p.hex()),
696 702 ('phase', p.phasestr())]
697 703 for p in pctxs]
698 704 f = _showcompatlist(context, mapping, 'parent', parents)
699 705 return _hybrid(f, prevs, lambda x: {'ctx': repo[x]},
700 706 lambda x: scmutil.formatchangeid(repo[x]), keytype=int)
701 707
702 708 @templatekeyword('phase', requires={'ctx'})
703 709 def showphase(context, mapping):
704 710 """String. The changeset phase name."""
705 711 ctx = context.resource(mapping, 'ctx')
706 712 return ctx.phasestr()
707 713
708 714 @templatekeyword('phaseidx', requires={'ctx'})
709 715 def showphaseidx(context, mapping):
710 716 """Integer. The changeset phase index. (ADVANCED)"""
711 717 ctx = context.resource(mapping, 'ctx')
712 718 return ctx.phase()
713 719
714 720 @templatekeyword('rev', requires={'ctx'})
715 721 def showrev(context, mapping):
716 722 """Integer. The repository-local changeset revision number."""
717 723 ctx = context.resource(mapping, 'ctx')
718 724 return scmutil.intrev(ctx)
719 725
720 726 def showrevslist(context, mapping, name, revs):
721 727 """helper to generate a list of revisions in which a mapped template will
722 728 be evaluated"""
723 729 repo = context.resource(mapping, 'repo')
724 730 f = _showcompatlist(context, mapping, name, ['%d' % r for r in revs])
725 731 return _hybrid(f, revs,
726 732 lambda x: {name: x, 'ctx': repo[x]},
727 733 pycompat.identity, keytype=int)
728 734
729 735 @templatekeyword('subrepos', requires={'ctx'})
730 736 def showsubrepos(context, mapping):
731 737 """List of strings. Updated subrepositories in the changeset."""
732 738 ctx = context.resource(mapping, 'ctx')
733 739 substate = ctx.substate
734 740 if not substate:
735 741 return compatlist(context, mapping, 'subrepo', [])
736 742 psubstate = ctx.parents()[0].substate or {}
737 743 subrepos = []
738 744 for sub in substate:
739 745 if sub not in psubstate or substate[sub] != psubstate[sub]:
740 746 subrepos.append(sub) # modified or newly added in ctx
741 747 for sub in psubstate:
742 748 if sub not in substate:
743 749 subrepos.append(sub) # removed in ctx
744 750 return compatlist(context, mapping, 'subrepo', sorted(subrepos))
745 751
746 752 # don't remove "showtags" definition, even though namespaces will put
747 753 # a helper function for "tags" keyword into "keywords" map automatically,
748 754 # because online help text is built without namespaces initialization
749 755 @templatekeyword('tags', requires={'repo', 'ctx'})
750 756 def showtags(context, mapping):
751 757 """List of strings. Any tags associated with the changeset."""
752 758 return shownames(context, mapping, 'tags')
753 759
754 760 @templatekeyword('termwidth', requires={'ui'})
755 761 def showtermwidth(context, mapping):
756 762 """Integer. The width of the current terminal."""
757 763 ui = context.resource(mapping, 'ui')
758 764 return ui.termwidth()
759 765
760 766 @templatekeyword('user', requires={'ctx'})
761 767 def showuser(context, mapping):
762 768 """String. The unmodified author of the changeset."""
763 769 ctx = context.resource(mapping, 'ctx')
764 770 return ctx.user()
765 771
766 772 @templatekeyword('instabilities', requires={'ctx'})
767 773 def showinstabilities(context, mapping):
768 774 """List of strings. Evolution instabilities affecting the changeset.
769 775 (EXPERIMENTAL)
770 776 """
771 777 ctx = context.resource(mapping, 'ctx')
772 778 return compatlist(context, mapping, 'instability', ctx.instabilities(),
773 779 plural='instabilities')
774 780
775 781 @templatekeyword('verbosity', requires={'ui'})
776 782 def showverbosity(context, mapping):
777 783 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
778 784 or ''."""
779 785 ui = context.resource(mapping, 'ui')
780 786 # see logcmdutil.changesettemplater for priority of these flags
781 787 if ui.debugflag:
782 788 return 'debug'
783 789 elif ui.quiet:
784 790 return 'quiet'
785 791 elif ui.verbose:
786 792 return 'verbose'
787 793 return ''
788 794
789 795 @templatekeyword('whyunstable', requires={'repo', 'ctx'})
790 796 def showwhyunstable(context, mapping):
791 797 """List of dicts explaining all instabilities of a changeset.
792 798 (EXPERIMENTAL)
793 799 """
794 800 repo = context.resource(mapping, 'repo')
795 801 ctx = context.resource(mapping, 'ctx')
796 802
797 803 def formatnode(ctx):
798 804 return '%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr())
799 805
800 806 entries = obsutil.whyunstable(repo, ctx)
801 807
802 808 for entry in entries:
803 809 if entry.get('divergentnodes'):
804 810 dnodes = entry['divergentnodes']
805 811 dnhybrid = _hybrid(None, [dnode.hex() for dnode in dnodes],
806 812 lambda x: {'ctx': repo[x]},
807 813 lambda x: formatnode(repo[x]))
808 814 entry['divergentnodes'] = dnhybrid
809 815
810 816 tmpl = ('{instability}:{if(divergentnodes, " ")}{divergentnodes} '
811 817 '{reason} {node|short}')
812 818 return templateutil.mappinglist(entries, tmpl=tmpl, sep='\n')
813 819
814 820 def loadkeyword(ui, extname, registrarobj):
815 821 """Load template keyword from specified registrarobj
816 822 """
817 823 for name, func in registrarobj._table.iteritems():
818 824 keywords[name] = func
819 825
820 826 # tell hggettext to extract docstrings from these functions:
821 827 i18nfunctions = keywords.values()
@@ -1,1264 +1,1273 b''
1 1 Test template keywords
2 2 ======================
3 3
4 4 $ hg init a
5 5 $ cd a
6 6 $ echo a > a
7 7 $ hg add a
8 8 $ echo line 1 > b
9 9 $ echo line 2 >> b
10 10 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
11 11
12 12 $ hg add b
13 13 $ echo other 1 > c
14 14 $ echo other 2 >> c
15 15 $ echo >> c
16 16 $ echo other 3 >> c
17 17 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
18 18
19 19 $ hg add c
20 20 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
21 21 $ echo c >> c
22 22 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
23 23
24 24 $ echo foo > .hg/branch
25 25 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
26 26
27 27 $ hg co -q 3
28 28 $ echo other 4 >> d
29 29 $ hg add d
30 30 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
31 31
32 32 $ hg merge -q foo
33 33 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
34 34
35 35 Second branch starting at nullrev:
36 36
37 37 $ hg update null
38 38 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
39 39 $ echo second > second
40 40 $ hg add second
41 41 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
42 42 created new head
43 43
44 44 $ echo third > third
45 45 $ hg add third
46 46 $ hg mv second fourth
47 47 $ hg commit -m third -d "2020-01-01 10:01"
48 48
49 49 Working-directory revision has special identifiers, though they are still
50 50 experimental:
51 51
52 52 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
53 53 2147483647:ffffffffffffffffffffffffffffffffffffffff
54 54
55 55 Some keywords are invalid for working-directory revision, but they should
56 56 never cause crash:
57 57
58 58 $ hg log -r 'wdir()' -T '{manifest}\n'
59 59
60 60
61 61 Check that {phase} works correctly on parents:
62 62
63 63 $ cat << EOF > parentphase
64 64 > changeset_debug = '{rev} ({phase}):{parents}\n'
65 65 > parent = ' {rev} ({phase})'
66 66 > EOF
67 67 $ hg phase -r 5 --public
68 68 $ hg phase -r 7 --secret --force
69 69 $ hg log --debug -G --style ./parentphase
70 70 @ 8 (secret): 7 (secret) -1 (public)
71 71 |
72 72 o 7 (secret): -1 (public) -1 (public)
73 73
74 74 o 6 (draft): 5 (public) 4 (draft)
75 75 |\
76 76 | o 5 (public): 3 (public) -1 (public)
77 77 | |
78 78 o | 4 (draft): 3 (public) -1 (public)
79 79 |/
80 80 o 3 (public): 2 (public) -1 (public)
81 81 |
82 82 o 2 (public): 1 (public) -1 (public)
83 83 |
84 84 o 1 (public): 0 (public) -1 (public)
85 85 |
86 86 o 0 (public): -1 (public) -1 (public)
87 87
88 88
89 89 Keys work:
90 90
91 91 $ for key in author branch branches date desc file_adds file_dels file_mods \
92 92 > file_copies file_copies_switch files \
93 93 > manifest node parents rev tags diffstat extras \
94 94 > p1rev p2rev p1node p2node user; do
95 95 > for mode in '' --verbose --debug; do
96 96 > hg log $mode --template "$key$mode: {$key}\n"
97 97 > done
98 98 > done
99 99 author: test
100 100 author: User Name <user@hostname>
101 101 author: person
102 102 author: person
103 103 author: person
104 104 author: person
105 105 author: other@place
106 106 author: A. N. Other <other@place>
107 107 author: User Name <user@hostname>
108 108 author--verbose: test
109 109 author--verbose: User Name <user@hostname>
110 110 author--verbose: person
111 111 author--verbose: person
112 112 author--verbose: person
113 113 author--verbose: person
114 114 author--verbose: other@place
115 115 author--verbose: A. N. Other <other@place>
116 116 author--verbose: User Name <user@hostname>
117 117 author--debug: test
118 118 author--debug: User Name <user@hostname>
119 119 author--debug: person
120 120 author--debug: person
121 121 author--debug: person
122 122 author--debug: person
123 123 author--debug: other@place
124 124 author--debug: A. N. Other <other@place>
125 125 author--debug: User Name <user@hostname>
126 126 branch: default
127 127 branch: default
128 128 branch: default
129 129 branch: default
130 130 branch: foo
131 131 branch: default
132 132 branch: default
133 133 branch: default
134 134 branch: default
135 135 branch--verbose: default
136 136 branch--verbose: default
137 137 branch--verbose: default
138 138 branch--verbose: default
139 139 branch--verbose: foo
140 140 branch--verbose: default
141 141 branch--verbose: default
142 142 branch--verbose: default
143 143 branch--verbose: default
144 144 branch--debug: default
145 145 branch--debug: default
146 146 branch--debug: default
147 147 branch--debug: default
148 148 branch--debug: foo
149 149 branch--debug: default
150 150 branch--debug: default
151 151 branch--debug: default
152 152 branch--debug: default
153 153 branches:
154 154 branches:
155 155 branches:
156 156 branches:
157 157 branches: foo
158 158 branches:
159 159 branches:
160 160 branches:
161 161 branches:
162 162 branches--verbose:
163 163 branches--verbose:
164 164 branches--verbose:
165 165 branches--verbose:
166 166 branches--verbose: foo
167 167 branches--verbose:
168 168 branches--verbose:
169 169 branches--verbose:
170 170 branches--verbose:
171 171 branches--debug:
172 172 branches--debug:
173 173 branches--debug:
174 174 branches--debug:
175 175 branches--debug: foo
176 176 branches--debug:
177 177 branches--debug:
178 178 branches--debug:
179 179 branches--debug:
180 180 date: 1577872860.00
181 181 date: 1000000.00
182 182 date: 1500001.00
183 183 date: 1500000.00
184 184 date: 1400000.00
185 185 date: 1300000.00
186 186 date: 1200000.00
187 187 date: 1100000.00
188 188 date: 1000000.00
189 189 date--verbose: 1577872860.00
190 190 date--verbose: 1000000.00
191 191 date--verbose: 1500001.00
192 192 date--verbose: 1500000.00
193 193 date--verbose: 1400000.00
194 194 date--verbose: 1300000.00
195 195 date--verbose: 1200000.00
196 196 date--verbose: 1100000.00
197 197 date--verbose: 1000000.00
198 198 date--debug: 1577872860.00
199 199 date--debug: 1000000.00
200 200 date--debug: 1500001.00
201 201 date--debug: 1500000.00
202 202 date--debug: 1400000.00
203 203 date--debug: 1300000.00
204 204 date--debug: 1200000.00
205 205 date--debug: 1100000.00
206 206 date--debug: 1000000.00
207 207 desc: third
208 208 desc: second
209 209 desc: merge
210 210 desc: new head
211 211 desc: new branch
212 212 desc: no user, no domain
213 213 desc: no person
214 214 desc: other 1
215 215 other 2
216 216
217 217 other 3
218 218 desc: line 1
219 219 line 2
220 220 desc--verbose: third
221 221 desc--verbose: second
222 222 desc--verbose: merge
223 223 desc--verbose: new head
224 224 desc--verbose: new branch
225 225 desc--verbose: no user, no domain
226 226 desc--verbose: no person
227 227 desc--verbose: other 1
228 228 other 2
229 229
230 230 other 3
231 231 desc--verbose: line 1
232 232 line 2
233 233 desc--debug: third
234 234 desc--debug: second
235 235 desc--debug: merge
236 236 desc--debug: new head
237 237 desc--debug: new branch
238 238 desc--debug: no user, no domain
239 239 desc--debug: no person
240 240 desc--debug: other 1
241 241 other 2
242 242
243 243 other 3
244 244 desc--debug: line 1
245 245 line 2
246 246 file_adds: fourth third
247 247 file_adds: second
248 248 file_adds:
249 249 file_adds: d
250 250 file_adds:
251 251 file_adds:
252 252 file_adds: c
253 253 file_adds: b
254 254 file_adds: a
255 255 file_adds--verbose: fourth third
256 256 file_adds--verbose: second
257 257 file_adds--verbose:
258 258 file_adds--verbose: d
259 259 file_adds--verbose:
260 260 file_adds--verbose:
261 261 file_adds--verbose: c
262 262 file_adds--verbose: b
263 263 file_adds--verbose: a
264 264 file_adds--debug: fourth third
265 265 file_adds--debug: second
266 266 file_adds--debug:
267 267 file_adds--debug: d
268 268 file_adds--debug:
269 269 file_adds--debug:
270 270 file_adds--debug: c
271 271 file_adds--debug: b
272 272 file_adds--debug: a
273 273 file_dels: second
274 274 file_dels:
275 275 file_dels:
276 276 file_dels:
277 277 file_dels:
278 278 file_dels:
279 279 file_dels:
280 280 file_dels:
281 281 file_dels:
282 282 file_dels--verbose: second
283 283 file_dels--verbose:
284 284 file_dels--verbose:
285 285 file_dels--verbose:
286 286 file_dels--verbose:
287 287 file_dels--verbose:
288 288 file_dels--verbose:
289 289 file_dels--verbose:
290 290 file_dels--verbose:
291 291 file_dels--debug: second
292 292 file_dels--debug:
293 293 file_dels--debug:
294 294 file_dels--debug:
295 295 file_dels--debug:
296 296 file_dels--debug:
297 297 file_dels--debug:
298 298 file_dels--debug:
299 299 file_dels--debug:
300 300 file_mods:
301 301 file_mods:
302 302 file_mods:
303 303 file_mods:
304 304 file_mods:
305 305 file_mods: c
306 306 file_mods:
307 307 file_mods:
308 308 file_mods:
309 309 file_mods--verbose:
310 310 file_mods--verbose:
311 311 file_mods--verbose:
312 312 file_mods--verbose:
313 313 file_mods--verbose:
314 314 file_mods--verbose: c
315 315 file_mods--verbose:
316 316 file_mods--verbose:
317 317 file_mods--verbose:
318 318 file_mods--debug:
319 319 file_mods--debug:
320 320 file_mods--debug:
321 321 file_mods--debug:
322 322 file_mods--debug:
323 323 file_mods--debug: c
324 324 file_mods--debug:
325 325 file_mods--debug:
326 326 file_mods--debug:
327 327 file_copies: fourth (second)
328 328 file_copies:
329 329 file_copies:
330 330 file_copies:
331 331 file_copies:
332 332 file_copies:
333 333 file_copies:
334 334 file_copies:
335 335 file_copies:
336 336 file_copies--verbose: fourth (second)
337 337 file_copies--verbose:
338 338 file_copies--verbose:
339 339 file_copies--verbose:
340 340 file_copies--verbose:
341 341 file_copies--verbose:
342 342 file_copies--verbose:
343 343 file_copies--verbose:
344 344 file_copies--verbose:
345 345 file_copies--debug: fourth (second)
346 346 file_copies--debug:
347 347 file_copies--debug:
348 348 file_copies--debug:
349 349 file_copies--debug:
350 350 file_copies--debug:
351 351 file_copies--debug:
352 352 file_copies--debug:
353 353 file_copies--debug:
354 354 file_copies_switch:
355 355 file_copies_switch:
356 356 file_copies_switch:
357 357 file_copies_switch:
358 358 file_copies_switch:
359 359 file_copies_switch:
360 360 file_copies_switch:
361 361 file_copies_switch:
362 362 file_copies_switch:
363 363 file_copies_switch--verbose:
364 364 file_copies_switch--verbose:
365 365 file_copies_switch--verbose:
366 366 file_copies_switch--verbose:
367 367 file_copies_switch--verbose:
368 368 file_copies_switch--verbose:
369 369 file_copies_switch--verbose:
370 370 file_copies_switch--verbose:
371 371 file_copies_switch--verbose:
372 372 file_copies_switch--debug:
373 373 file_copies_switch--debug:
374 374 file_copies_switch--debug:
375 375 file_copies_switch--debug:
376 376 file_copies_switch--debug:
377 377 file_copies_switch--debug:
378 378 file_copies_switch--debug:
379 379 file_copies_switch--debug:
380 380 file_copies_switch--debug:
381 381 files: fourth second third
382 382 files: second
383 383 files:
384 384 files: d
385 385 files:
386 386 files: c
387 387 files: c
388 388 files: b
389 389 files: a
390 390 files--verbose: fourth second third
391 391 files--verbose: second
392 392 files--verbose:
393 393 files--verbose: d
394 394 files--verbose:
395 395 files--verbose: c
396 396 files--verbose: c
397 397 files--verbose: b
398 398 files--verbose: a
399 399 files--debug: fourth second third
400 400 files--debug: second
401 401 files--debug:
402 402 files--debug: d
403 403 files--debug:
404 404 files--debug: c
405 405 files--debug: c
406 406 files--debug: b
407 407 files--debug: a
408 408 manifest: 6:94961b75a2da
409 409 manifest: 5:f2dbc354b94e
410 410 manifest: 4:4dc3def4f9b4
411 411 manifest: 4:4dc3def4f9b4
412 412 manifest: 3:cb5a1327723b
413 413 manifest: 3:cb5a1327723b
414 414 manifest: 2:6e0e82995c35
415 415 manifest: 1:4e8d705b1e53
416 416 manifest: 0:a0c8bcbbb45c
417 417 manifest--verbose: 6:94961b75a2da
418 418 manifest--verbose: 5:f2dbc354b94e
419 419 manifest--verbose: 4:4dc3def4f9b4
420 420 manifest--verbose: 4:4dc3def4f9b4
421 421 manifest--verbose: 3:cb5a1327723b
422 422 manifest--verbose: 3:cb5a1327723b
423 423 manifest--verbose: 2:6e0e82995c35
424 424 manifest--verbose: 1:4e8d705b1e53
425 425 manifest--verbose: 0:a0c8bcbbb45c
426 426 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
427 427 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
428 428 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
429 429 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
430 430 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
431 431 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
432 432 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
433 433 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
434 434 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
435 435 node: 95c24699272ef57d062b8bccc32c878bf841784a
436 436 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
437 437 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
438 438 node: 13207e5a10d9fd28ec424934298e176197f2c67f
439 439 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
440 440 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
441 441 node: 97054abb4ab824450e9164180baf491ae0078465
442 442 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
443 443 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
444 444 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
445 445 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
446 446 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
447 447 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
448 448 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
449 449 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
450 450 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
451 451 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
452 452 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
453 453 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
454 454 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
455 455 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
456 456 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
457 457 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
458 458 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
459 459 node--debug: 97054abb4ab824450e9164180baf491ae0078465
460 460 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
461 461 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
462 462 parents:
463 463 parents: -1:000000000000
464 464 parents: 5:13207e5a10d9 4:bbe44766e73d
465 465 parents: 3:10e46f2dcbf4
466 466 parents:
467 467 parents:
468 468 parents:
469 469 parents:
470 470 parents:
471 471 parents--verbose:
472 472 parents--verbose: -1:000000000000
473 473 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
474 474 parents--verbose: 3:10e46f2dcbf4
475 475 parents--verbose:
476 476 parents--verbose:
477 477 parents--verbose:
478 478 parents--verbose:
479 479 parents--verbose:
480 480 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
481 481 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
482 482 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
483 483 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
484 484 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
485 485 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
486 486 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
487 487 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
488 488 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
489 489 rev: 8
490 490 rev: 7
491 491 rev: 6
492 492 rev: 5
493 493 rev: 4
494 494 rev: 3
495 495 rev: 2
496 496 rev: 1
497 497 rev: 0
498 498 rev--verbose: 8
499 499 rev--verbose: 7
500 500 rev--verbose: 6
501 501 rev--verbose: 5
502 502 rev--verbose: 4
503 503 rev--verbose: 3
504 504 rev--verbose: 2
505 505 rev--verbose: 1
506 506 rev--verbose: 0
507 507 rev--debug: 8
508 508 rev--debug: 7
509 509 rev--debug: 6
510 510 rev--debug: 5
511 511 rev--debug: 4
512 512 rev--debug: 3
513 513 rev--debug: 2
514 514 rev--debug: 1
515 515 rev--debug: 0
516 516 tags: tip
517 517 tags:
518 518 tags:
519 519 tags:
520 520 tags:
521 521 tags:
522 522 tags:
523 523 tags:
524 524 tags:
525 525 tags--verbose: tip
526 526 tags--verbose:
527 527 tags--verbose:
528 528 tags--verbose:
529 529 tags--verbose:
530 530 tags--verbose:
531 531 tags--verbose:
532 532 tags--verbose:
533 533 tags--verbose:
534 534 tags--debug: tip
535 535 tags--debug:
536 536 tags--debug:
537 537 tags--debug:
538 538 tags--debug:
539 539 tags--debug:
540 540 tags--debug:
541 541 tags--debug:
542 542 tags--debug:
543 543 diffstat: 3: +2/-1
544 544 diffstat: 1: +1/-0
545 545 diffstat: 0: +0/-0
546 546 diffstat: 1: +1/-0
547 547 diffstat: 0: +0/-0
548 548 diffstat: 1: +1/-0
549 549 diffstat: 1: +4/-0
550 550 diffstat: 1: +2/-0
551 551 diffstat: 1: +1/-0
552 552 diffstat--verbose: 3: +2/-1
553 553 diffstat--verbose: 1: +1/-0
554 554 diffstat--verbose: 0: +0/-0
555 555 diffstat--verbose: 1: +1/-0
556 556 diffstat--verbose: 0: +0/-0
557 557 diffstat--verbose: 1: +1/-0
558 558 diffstat--verbose: 1: +4/-0
559 559 diffstat--verbose: 1: +2/-0
560 560 diffstat--verbose: 1: +1/-0
561 561 diffstat--debug: 3: +2/-1
562 562 diffstat--debug: 1: +1/-0
563 563 diffstat--debug: 0: +0/-0
564 564 diffstat--debug: 1: +1/-0
565 565 diffstat--debug: 0: +0/-0
566 566 diffstat--debug: 1: +1/-0
567 567 diffstat--debug: 1: +4/-0
568 568 diffstat--debug: 1: +2/-0
569 569 diffstat--debug: 1: +1/-0
570 570 extras: branch=default
571 571 extras: branch=default
572 572 extras: branch=default
573 573 extras: branch=default
574 574 extras: branch=foo
575 575 extras: branch=default
576 576 extras: branch=default
577 577 extras: branch=default
578 578 extras: branch=default
579 579 extras--verbose: branch=default
580 580 extras--verbose: branch=default
581 581 extras--verbose: branch=default
582 582 extras--verbose: branch=default
583 583 extras--verbose: branch=foo
584 584 extras--verbose: branch=default
585 585 extras--verbose: branch=default
586 586 extras--verbose: branch=default
587 587 extras--verbose: branch=default
588 588 extras--debug: branch=default
589 589 extras--debug: branch=default
590 590 extras--debug: branch=default
591 591 extras--debug: branch=default
592 592 extras--debug: branch=foo
593 593 extras--debug: branch=default
594 594 extras--debug: branch=default
595 595 extras--debug: branch=default
596 596 extras--debug: branch=default
597 597 p1rev: 7
598 598 p1rev: -1
599 599 p1rev: 5
600 600 p1rev: 3
601 601 p1rev: 3
602 602 p1rev: 2
603 603 p1rev: 1
604 604 p1rev: 0
605 605 p1rev: -1
606 606 p1rev--verbose: 7
607 607 p1rev--verbose: -1
608 608 p1rev--verbose: 5
609 609 p1rev--verbose: 3
610 610 p1rev--verbose: 3
611 611 p1rev--verbose: 2
612 612 p1rev--verbose: 1
613 613 p1rev--verbose: 0
614 614 p1rev--verbose: -1
615 615 p1rev--debug: 7
616 616 p1rev--debug: -1
617 617 p1rev--debug: 5
618 618 p1rev--debug: 3
619 619 p1rev--debug: 3
620 620 p1rev--debug: 2
621 621 p1rev--debug: 1
622 622 p1rev--debug: 0
623 623 p1rev--debug: -1
624 624 p2rev: -1
625 625 p2rev: -1
626 626 p2rev: 4
627 627 p2rev: -1
628 628 p2rev: -1
629 629 p2rev: -1
630 630 p2rev: -1
631 631 p2rev: -1
632 632 p2rev: -1
633 633 p2rev--verbose: -1
634 634 p2rev--verbose: -1
635 635 p2rev--verbose: 4
636 636 p2rev--verbose: -1
637 637 p2rev--verbose: -1
638 638 p2rev--verbose: -1
639 639 p2rev--verbose: -1
640 640 p2rev--verbose: -1
641 641 p2rev--verbose: -1
642 642 p2rev--debug: -1
643 643 p2rev--debug: -1
644 644 p2rev--debug: 4
645 645 p2rev--debug: -1
646 646 p2rev--debug: -1
647 647 p2rev--debug: -1
648 648 p2rev--debug: -1
649 649 p2rev--debug: -1
650 650 p2rev--debug: -1
651 651 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
652 652 p1node: 0000000000000000000000000000000000000000
653 653 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
654 654 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
655 655 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
656 656 p1node: 97054abb4ab824450e9164180baf491ae0078465
657 657 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
658 658 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
659 659 p1node: 0000000000000000000000000000000000000000
660 660 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
661 661 p1node--verbose: 0000000000000000000000000000000000000000
662 662 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
663 663 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
664 664 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
665 665 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
666 666 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
667 667 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
668 668 p1node--verbose: 0000000000000000000000000000000000000000
669 669 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
670 670 p1node--debug: 0000000000000000000000000000000000000000
671 671 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
672 672 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
673 673 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
674 674 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
675 675 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
676 676 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
677 677 p1node--debug: 0000000000000000000000000000000000000000
678 678 p2node: 0000000000000000000000000000000000000000
679 679 p2node: 0000000000000000000000000000000000000000
680 680 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
681 681 p2node: 0000000000000000000000000000000000000000
682 682 p2node: 0000000000000000000000000000000000000000
683 683 p2node: 0000000000000000000000000000000000000000
684 684 p2node: 0000000000000000000000000000000000000000
685 685 p2node: 0000000000000000000000000000000000000000
686 686 p2node: 0000000000000000000000000000000000000000
687 687 p2node--verbose: 0000000000000000000000000000000000000000
688 688 p2node--verbose: 0000000000000000000000000000000000000000
689 689 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
690 690 p2node--verbose: 0000000000000000000000000000000000000000
691 691 p2node--verbose: 0000000000000000000000000000000000000000
692 692 p2node--verbose: 0000000000000000000000000000000000000000
693 693 p2node--verbose: 0000000000000000000000000000000000000000
694 694 p2node--verbose: 0000000000000000000000000000000000000000
695 695 p2node--verbose: 0000000000000000000000000000000000000000
696 696 p2node--debug: 0000000000000000000000000000000000000000
697 697 p2node--debug: 0000000000000000000000000000000000000000
698 698 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
699 699 p2node--debug: 0000000000000000000000000000000000000000
700 700 p2node--debug: 0000000000000000000000000000000000000000
701 701 p2node--debug: 0000000000000000000000000000000000000000
702 702 p2node--debug: 0000000000000000000000000000000000000000
703 703 p2node--debug: 0000000000000000000000000000000000000000
704 704 p2node--debug: 0000000000000000000000000000000000000000
705 705 user: test
706 706 user: User Name <user@hostname>
707 707 user: person
708 708 user: person
709 709 user: person
710 710 user: person
711 711 user: other@place
712 712 user: A. N. Other <other@place>
713 713 user: User Name <user@hostname>
714 714 user--verbose: test
715 715 user--verbose: User Name <user@hostname>
716 716 user--verbose: person
717 717 user--verbose: person
718 718 user--verbose: person
719 719 user--verbose: person
720 720 user--verbose: other@place
721 721 user--verbose: A. N. Other <other@place>
722 722 user--verbose: User Name <user@hostname>
723 723 user--debug: test
724 724 user--debug: User Name <user@hostname>
725 725 user--debug: person
726 726 user--debug: person
727 727 user--debug: person
728 728 user--debug: person
729 729 user--debug: other@place
730 730 user--debug: A. N. Other <other@place>
731 731 user--debug: User Name <user@hostname>
732 732
733 733 Add a dummy commit to make up for the instability of the above:
734 734
735 735 $ echo a > a
736 736 $ hg add a
737 737 $ hg ci -m future
738 738
739 739 Add a commit that does all possible modifications at once
740 740
741 741 $ echo modify >> third
742 742 $ touch b
743 743 $ hg add b
744 744 $ hg mv fourth fifth
745 745 $ hg rm a
746 746 $ hg ci -m "Modify, add, remove, rename"
747 747
748 748 Test files list:
749 749
750 750 $ hg log -l1 -T '{join(file_mods, " ")}\n'
751 751 third
752 752 $ hg log -l1 -T '{file_mods % "{file}\n"}'
753 753 third
754 754 $ hg log -l1 -T '{file_mods % "{path}\n"}'
755 755 third
756 756
757 757 $ hg log -l1 -T '{join(files, " ")}\n'
758 758 a b fifth fourth third
759 759 $ hg log -l1 -T '{files % "{file}\n"}'
760 760 a
761 761 b
762 762 fifth
763 763 fourth
764 764 third
765 765 $ hg log -l1 -T '{files % "{path}\n"}'
766 766 a
767 767 b
768 768 fifth
769 769 fourth
770 770 third
771 771
772 772 Test file copies dict:
773 773
774 774 $ hg log -r8 -T '{join(file_copies, " ")}\n'
775 775 fourth (second)
776 776 $ hg log -r8 -T '{file_copies % "{name} <- {source}\n"}'
777 777 fourth <- second
778 778 $ hg log -r8 -T '{file_copies % "{path} <- {source}\n"}'
779 779 fourth <- second
780 780
781 781 $ hg log -r8 -T '{join(file_copies_switch, " ")}\n'
782 782
783 783 $ hg log -r8 -C -T '{join(file_copies_switch, " ")}\n'
784 784 fourth (second)
785 785 $ hg log -r8 -C -T '{file_copies_switch % "{name} <- {source}\n"}'
786 786 fourth <- second
787 787 $ hg log -r8 -C -T '{file_copies_switch % "{path} <- {source}\n"}'
788 788 fourth <- second
789 789
790 Test file attributes:
791
792 $ hg log -l1 -T '{files % "{pad(size, 3, left=True)} {path}\n"}'
793 a
794 0 b
795 7 fifth
796 fourth
797 13 third
798
790 799 Test index keyword:
791 800
792 801 $ hg log -l 2 -T '{index + 10}{files % " {index}:{file}"}\n'
793 802 10 0:a 1:b 2:fifth 3:fourth 4:third
794 803 11 0:a
795 804
796 805 $ hg branches -T '{index} {branch}\n'
797 806 0 default
798 807 1 foo
799 808
800 809 ui verbosity:
801 810
802 811 $ hg log -l1 -T '{verbosity}\n'
803 812
804 813 $ hg log -l1 -T '{verbosity}\n' --debug
805 814 debug
806 815 $ hg log -l1 -T '{verbosity}\n' --quiet
807 816 quiet
808 817 $ hg log -l1 -T '{verbosity}\n' --verbose
809 818 verbose
810 819
811 820 $ cd ..
812 821
813 822 latesttag:
814 823
815 824 $ hg init latesttag
816 825 $ cd latesttag
817 826
818 827 $ echo a > file
819 828 $ hg ci -Am a -d '0 0'
820 829 adding file
821 830
822 831 $ echo b >> file
823 832 $ hg ci -m b -d '1 0'
824 833
825 834 $ echo c >> head1
826 835 $ hg ci -Am h1c -d '2 0'
827 836 adding head1
828 837
829 838 $ hg update -q 1
830 839 $ echo d >> head2
831 840 $ hg ci -Am h2d -d '3 0'
832 841 adding head2
833 842 created new head
834 843
835 844 $ echo e >> head2
836 845 $ hg ci -m h2e -d '4 0'
837 846
838 847 $ hg merge -q
839 848 $ hg ci -m merge -d '5 -3600'
840 849
841 850 No tag set:
842 851
843 852 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
844 853 @ 5: null+5
845 854 |\
846 855 | o 4: null+4
847 856 | |
848 857 | o 3: null+3
849 858 | |
850 859 o | 2: null+3
851 860 |/
852 861 o 1: null+2
853 862 |
854 863 o 0: null+1
855 864
856 865
857 866 One common tag: longest path wins for {latesttagdistance}:
858 867
859 868 $ hg tag -r 1 -m t1 -d '6 0' t1
860 869 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
861 870 @ 6: t1+4
862 871 |
863 872 o 5: t1+3
864 873 |\
865 874 | o 4: t1+2
866 875 | |
867 876 | o 3: t1+1
868 877 | |
869 878 o | 2: t1+1
870 879 |/
871 880 o 1: t1+0
872 881 |
873 882 o 0: null+1
874 883
875 884
876 885 One ancestor tag: closest wins:
877 886
878 887 $ hg tag -r 2 -m t2 -d '7 0' t2
879 888 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
880 889 @ 7: t2+3
881 890 |
882 891 o 6: t2+2
883 892 |
884 893 o 5: t2+1
885 894 |\
886 895 | o 4: t1+2
887 896 | |
888 897 | o 3: t1+1
889 898 | |
890 899 o | 2: t2+0
891 900 |/
892 901 o 1: t1+0
893 902 |
894 903 o 0: null+1
895 904
896 905
897 906 Two branch tags: more recent wins if same number of changes:
898 907
899 908 $ hg tag -r 3 -m t3 -d '8 0' t3
900 909 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
901 910 @ 8: t3+5
902 911 |
903 912 o 7: t3+4
904 913 |
905 914 o 6: t3+3
906 915 |
907 916 o 5: t3+2
908 917 |\
909 918 | o 4: t3+1
910 919 | |
911 920 | o 3: t3+0
912 921 | |
913 922 o | 2: t2+0
914 923 |/
915 924 o 1: t1+0
916 925 |
917 926 o 0: null+1
918 927
919 928
920 929 Two branch tags: fewest changes wins:
921 930
922 931 $ hg tag -r 4 -m t4 -d '4 0' t4 # older than t2, but should not matter
923 932 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
924 933 @ 9: t4+5,6
925 934 |
926 935 o 8: t4+4,5
927 936 |
928 937 o 7: t4+3,4
929 938 |
930 939 o 6: t4+2,3
931 940 |
932 941 o 5: t4+1,2
933 942 |\
934 943 | o 4: t4+0,0
935 944 | |
936 945 | o 3: t3+0,0
937 946 | |
938 947 o | 2: t2+0,0
939 948 |/
940 949 o 1: t1+0,0
941 950 |
942 951 o 0: null+1,1
943 952
944 953
945 954 Merged tag overrides:
946 955
947 956 $ hg tag -r 5 -m t5 -d '9 0' t5
948 957 $ hg tag -r 3 -m at3 -d '10 0' at3
949 958 $ hg log -G --template '{rev}: {latesttag}+{latesttagdistance}\n'
950 959 @ 11: t5+6
951 960 |
952 961 o 10: t5+5
953 962 |
954 963 o 9: t5+4
955 964 |
956 965 o 8: t5+3
957 966 |
958 967 o 7: t5+2
959 968 |
960 969 o 6: t5+1
961 970 |
962 971 o 5: t5+0
963 972 |\
964 973 | o 4: t4+0
965 974 | |
966 975 | o 3: at3:t3+0
967 976 | |
968 977 o | 2: t2+0
969 978 |/
970 979 o 1: t1+0
971 980 |
972 981 o 0: null+1
973 982
974 983
975 984 $ hg log -G --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
976 985 @ 11: t5+6,6
977 986 |
978 987 o 10: t5+5,5
979 988 |
980 989 o 9: t5+4,4
981 990 |
982 991 o 8: t5+3,3
983 992 |
984 993 o 7: t5+2,2
985 994 |
986 995 o 6: t5+1,1
987 996 |
988 997 o 5: t5+0,0
989 998 |\
990 999 | o 4: t4+0,0
991 1000 | |
992 1001 | o 3: at3+0,0 t3+0,0
993 1002 | |
994 1003 o | 2: t2+0,0
995 1004 |/
996 1005 o 1: t1+0,0
997 1006 |
998 1007 o 0: null+1,1
999 1008
1000 1009
1001 1010 $ cd ..
1002 1011
1003 1012 Set up repository containing template fragments in commit metadata:
1004 1013
1005 1014 $ hg init r
1006 1015 $ cd r
1007 1016 $ echo a > a
1008 1017 $ hg ci -Am '{rev}'
1009 1018 adding a
1010 1019
1011 1020 $ hg branch -q 'text.{rev}'
1012 1021 $ echo aa >> aa
1013 1022 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
1014 1023
1015 1024 Test termwidth:
1016 1025
1017 1026 $ COLUMNS=25 hg log -l1 --template '{fill(desc, termwidth, "{node|short}:", "termwidth.{rev}:")}'
1018 1027 bcc7ff960b8e:desc to be
1019 1028 termwidth.1:wrapped desc
1020 1029 termwidth.1:to be wrapped (no-eol)
1021 1030
1022 1031 Just one more commit:
1023 1032
1024 1033 $ echo b > b
1025 1034 $ hg ci -qAm b
1026 1035
1027 1036 Test 'originalnode'
1028 1037
1029 1038 $ hg log -r 1 -T '{revset("null") % "{node|short} {originalnode|short}"}\n'
1030 1039 000000000000 bcc7ff960b8e
1031 1040 $ hg log -r 0 -T '{manifest % "{node} {originalnode}"}\n'
1032 1041 a0c8bcbbb45c63b90b70ad007bf38961f64f2af0 f7769ec2ab975ad19684098ad1ffd9b81ecc71a1
1033 1042
1034 1043 Test active bookmark templating
1035 1044
1036 1045 $ hg book foo
1037 1046 $ hg book bar
1038 1047 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
1039 1048 2 bar* foo
1040 1049 1
1041 1050 0
1042 1051 $ hg log --template "{rev} {activebookmark}\n"
1043 1052 2 bar
1044 1053 1
1045 1054 0
1046 1055 $ hg bookmarks --inactive bar
1047 1056 $ hg log --template "{rev} {activebookmark}\n"
1048 1057 2
1049 1058 1
1050 1059 0
1051 1060 $ hg book -r1 baz
1052 1061 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
1053 1062 2 bar foo
1054 1063 1 baz
1055 1064 0
1056 1065 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
1057 1066 2 t
1058 1067 1 f
1059 1068 0 f
1060 1069
1061 1070 Test namespaces dict
1062 1071
1063 1072 $ hg --config extensions.revnamesext=$TESTDIR/revnamesext.py log -T '{rev}\n{namespaces % " {namespace} color={colorname} builtin={builtin}\n {join(names, ",")}\n"}\n'
1064 1073 2
1065 1074 bookmarks color=bookmark builtin=True
1066 1075 bar,foo
1067 1076 tags color=tag builtin=True
1068 1077 tip
1069 1078 branches color=branch builtin=True
1070 1079 text.{rev}
1071 1080 revnames color=revname builtin=False
1072 1081 r2
1073 1082
1074 1083 1
1075 1084 bookmarks color=bookmark builtin=True
1076 1085 baz
1077 1086 tags color=tag builtin=True
1078 1087
1079 1088 branches color=branch builtin=True
1080 1089 text.{rev}
1081 1090 revnames color=revname builtin=False
1082 1091 r1
1083 1092
1084 1093 0
1085 1094 bookmarks color=bookmark builtin=True
1086 1095
1087 1096 tags color=tag builtin=True
1088 1097
1089 1098 branches color=branch builtin=True
1090 1099 default
1091 1100 revnames color=revname builtin=False
1092 1101 r0
1093 1102
1094 1103 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
1095 1104 bookmarks: bar foo
1096 1105 tags: tip
1097 1106 branches: text.{rev}
1098 1107 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
1099 1108 bookmarks:
1100 1109 bar
1101 1110 foo
1102 1111 tags:
1103 1112 tip
1104 1113 branches:
1105 1114 text.{rev}
1106 1115 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
1107 1116 bar
1108 1117 foo
1109 1118 $ hg log -r2 -T '{namespaces.bookmarks % "{bookmark}\n"}'
1110 1119 bar
1111 1120 foo
1112 1121
1113 1122 $ cd ..
1114 1123
1115 1124 Test 'graphwidth' in 'hg log' on various topologies. The key here is that the
1116 1125 printed graphwidths 3, 5, 7, etc. should all line up in their respective
1117 1126 columns. We don't care about other aspects of the graph rendering here.
1118 1127
1119 1128 $ hg init graphwidth
1120 1129 $ cd graphwidth
1121 1130
1122 1131 $ wrappabletext="a a a a a a a a a a a a"
1123 1132
1124 1133 $ printf "first\n" > file
1125 1134 $ hg add file
1126 1135 $ hg commit -m "$wrappabletext"
1127 1136
1128 1137 $ printf "first\nsecond\n" > file
1129 1138 $ hg commit -m "$wrappabletext"
1130 1139
1131 1140 $ hg checkout 0
1132 1141 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1133 1142 $ printf "third\nfirst\n" > file
1134 1143 $ hg commit -m "$wrappabletext"
1135 1144 created new head
1136 1145
1137 1146 $ hg merge
1138 1147 merging file
1139 1148 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
1140 1149 (branch merge, don't forget to commit)
1141 1150
1142 1151 $ hg log --graph -T "{graphwidth}"
1143 1152 @ 3
1144 1153 |
1145 1154 | @ 5
1146 1155 |/
1147 1156 o 3
1148 1157
1149 1158 $ hg commit -m "$wrappabletext"
1150 1159
1151 1160 $ hg log --graph -T "{graphwidth}"
1152 1161 @ 5
1153 1162 |\
1154 1163 | o 5
1155 1164 | |
1156 1165 o | 5
1157 1166 |/
1158 1167 o 3
1159 1168
1160 1169
1161 1170 $ hg checkout 0
1162 1171 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1163 1172 $ printf "third\nfirst\nsecond\n" > file
1164 1173 $ hg commit -m "$wrappabletext"
1165 1174 created new head
1166 1175
1167 1176 $ hg log --graph -T "{graphwidth}"
1168 1177 @ 3
1169 1178 |
1170 1179 | o 7
1171 1180 | |\
1172 1181 +---o 7
1173 1182 | |
1174 1183 | o 5
1175 1184 |/
1176 1185 o 3
1177 1186
1178 1187
1179 1188 $ hg log --graph -T "{graphwidth}" -r 3
1180 1189 o 5
1181 1190 |\
1182 1191 ~ ~
1183 1192
1184 1193 $ hg log --graph -T "{graphwidth}" -r 1
1185 1194 o 3
1186 1195 |
1187 1196 ~
1188 1197
1189 1198 $ hg merge
1190 1199 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1191 1200 (branch merge, don't forget to commit)
1192 1201 $ hg commit -m "$wrappabletext"
1193 1202
1194 1203 $ printf "seventh\n" >> file
1195 1204 $ hg commit -m "$wrappabletext"
1196 1205
1197 1206 $ hg log --graph -T "{graphwidth}"
1198 1207 @ 3
1199 1208 |
1200 1209 o 5
1201 1210 |\
1202 1211 | o 5
1203 1212 | |
1204 1213 o | 7
1205 1214 |\ \
1206 1215 | o | 7
1207 1216 | |/
1208 1217 o / 5
1209 1218 |/
1210 1219 o 3
1211 1220
1212 1221
1213 1222 The point of graphwidth is to allow wrapping that accounts for the space taken
1214 1223 by the graph.
1215 1224
1216 1225 $ COLUMNS=10 hg log --graph -T "{fill(desc, termwidth - graphwidth)}"
1217 1226 @ a a a a
1218 1227 | a a a a
1219 1228 | a a a a
1220 1229 o a a a
1221 1230 |\ a a a
1222 1231 | | a a a
1223 1232 | | a a a
1224 1233 | o a a a
1225 1234 | | a a a
1226 1235 | | a a a
1227 1236 | | a a a
1228 1237 o | a a
1229 1238 |\ \ a a
1230 1239 | | | a a
1231 1240 | | | a a
1232 1241 | | | a a
1233 1242 | | | a a
1234 1243 | o | a a
1235 1244 | |/ a a
1236 1245 | | a a
1237 1246 | | a a
1238 1247 | | a a
1239 1248 | | a a
1240 1249 o | a a a
1241 1250 |/ a a a
1242 1251 | a a a
1243 1252 | a a a
1244 1253 o a a a a
1245 1254 a a a a
1246 1255 a a a a
1247 1256
1248 1257 Something tricky happens when there are elided nodes; the next drawn row of
1249 1258 edges can be more than one column wider, but the graph width only increases by
1250 1259 one column. The remaining columns are added in between the nodes.
1251 1260
1252 1261 $ hg log --graph -T "{graphwidth}" -r "0|2|4|5"
1253 1262 o 5
1254 1263 |\
1255 1264 | \
1256 1265 | :\
1257 1266 o : : 7
1258 1267 :/ /
1259 1268 : o 5
1260 1269 :/
1261 1270 o 3
1262 1271
1263 1272
1264 1273 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now