##// END OF EJS Templates
templatekw: remove pycompat.iteritems()...
Gregory Szorc -
r49785:e6df205a default
parent child Browse files
Show More
@@ -1,1031 +1,1031 b''
1 # templatekw.py - common changeset template keywords
1 # templatekw.py - common changeset template keywords
2 #
2 #
3 # Copyright 2005-2009 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2009 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8
8
9 from .i18n import _
9 from .i18n import _
10 from .node import (
10 from .node import (
11 hex,
11 hex,
12 wdirrev,
12 wdirrev,
13 )
13 )
14
14
15 from . import (
15 from . import (
16 diffutil,
16 diffutil,
17 encoding,
17 encoding,
18 error,
18 error,
19 hbisect,
19 hbisect,
20 i18n,
20 i18n,
21 obsutil,
21 obsutil,
22 patch,
22 patch,
23 pycompat,
23 pycompat,
24 registrar,
24 registrar,
25 scmutil,
25 scmutil,
26 templateutil,
26 templateutil,
27 util,
27 util,
28 )
28 )
29 from .utils import (
29 from .utils import (
30 stringutil,
30 stringutil,
31 urlutil,
31 urlutil,
32 )
32 )
33
33
34 _hybrid = templateutil.hybrid
34 _hybrid = templateutil.hybrid
35 hybriddict = templateutil.hybriddict
35 hybriddict = templateutil.hybriddict
36 hybridlist = templateutil.hybridlist
36 hybridlist = templateutil.hybridlist
37 compatdict = templateutil.compatdict
37 compatdict = templateutil.compatdict
38 compatlist = templateutil.compatlist
38 compatlist = templateutil.compatlist
39 _showcompatlist = templateutil._showcompatlist
39 _showcompatlist = templateutil._showcompatlist
40
40
41
41
42 def getlatesttags(context, mapping, pattern=None):
42 def getlatesttags(context, mapping, pattern=None):
43 '''return date, distance and name for the latest tag of rev'''
43 '''return date, distance and name for the latest tag of rev'''
44 repo = context.resource(mapping, b'repo')
44 repo = context.resource(mapping, b'repo')
45 ctx = context.resource(mapping, b'ctx')
45 ctx = context.resource(mapping, b'ctx')
46 cache = context.resource(mapping, b'cache')
46 cache = context.resource(mapping, b'cache')
47
47
48 cachename = b'latesttags'
48 cachename = b'latesttags'
49 if pattern is not None:
49 if pattern is not None:
50 cachename += b'-' + pattern
50 cachename += b'-' + pattern
51 match = stringutil.stringmatcher(pattern)[2]
51 match = stringutil.stringmatcher(pattern)[2]
52 else:
52 else:
53 match = util.always
53 match = util.always
54
54
55 if cachename not in cache:
55 if cachename not in cache:
56 # Cache mapping from rev to a tuple with tag date, tag
56 # Cache mapping from rev to a tuple with tag date, tag
57 # distance and tag name
57 # distance and tag name
58 cache[cachename] = {-1: (0, 0, [b'null'])}
58 cache[cachename] = {-1: (0, 0, [b'null'])}
59 latesttags = cache[cachename]
59 latesttags = cache[cachename]
60
60
61 rev = ctx.rev()
61 rev = ctx.rev()
62 todo = [rev]
62 todo = [rev]
63 while todo:
63 while todo:
64 rev = todo.pop()
64 rev = todo.pop()
65 if rev in latesttags:
65 if rev in latesttags:
66 continue
66 continue
67 ctx = repo[rev]
67 ctx = repo[rev]
68 tags = [
68 tags = [
69 t
69 t
70 for t in ctx.tags()
70 for t in ctx.tags()
71 if (repo.tagtype(t) and repo.tagtype(t) != b'local' and match(t))
71 if (repo.tagtype(t) and repo.tagtype(t) != b'local' and match(t))
72 ]
72 ]
73 if tags:
73 if tags:
74 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
74 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
75 continue
75 continue
76 try:
76 try:
77 ptags = [latesttags[p.rev()] for p in ctx.parents()]
77 ptags = [latesttags[p.rev()] for p in ctx.parents()]
78 if len(ptags) > 1:
78 if len(ptags) > 1:
79 if ptags[0][2] == ptags[1][2]:
79 if ptags[0][2] == ptags[1][2]:
80 # The tuples are laid out so the right one can be found by
80 # The tuples are laid out so the right one can be found by
81 # comparison in this case.
81 # comparison in this case.
82 pdate, pdist, ptag = max(ptags)
82 pdate, pdist, ptag = max(ptags)
83 else:
83 else:
84
84
85 def key(x):
85 def key(x):
86 tag = x[2][0]
86 tag = x[2][0]
87 if ctx.rev() is None:
87 if ctx.rev() is None:
88 # only() doesn't support wdir
88 # only() doesn't support wdir
89 prevs = [c.rev() for c in ctx.parents()]
89 prevs = [c.rev() for c in ctx.parents()]
90 changes = repo.revs(b'only(%ld, %s)', prevs, tag)
90 changes = repo.revs(b'only(%ld, %s)', prevs, tag)
91 changessincetag = len(changes) + 1
91 changessincetag = len(changes) + 1
92 else:
92 else:
93 changes = repo.revs(b'only(%d, %s)', ctx.rev(), tag)
93 changes = repo.revs(b'only(%d, %s)', ctx.rev(), tag)
94 changessincetag = len(changes)
94 changessincetag = len(changes)
95 # Smallest number of changes since tag wins. Date is
95 # Smallest number of changes since tag wins. Date is
96 # used as tiebreaker.
96 # used as tiebreaker.
97 return [-changessincetag, x[0]]
97 return [-changessincetag, x[0]]
98
98
99 pdate, pdist, ptag = max(ptags, key=key)
99 pdate, pdist, ptag = max(ptags, key=key)
100 else:
100 else:
101 pdate, pdist, ptag = ptags[0]
101 pdate, pdist, ptag = ptags[0]
102 except KeyError:
102 except KeyError:
103 # Cache miss - recurse
103 # Cache miss - recurse
104 todo.append(rev)
104 todo.append(rev)
105 todo.extend(p.rev() for p in ctx.parents())
105 todo.extend(p.rev() for p in ctx.parents())
106 continue
106 continue
107 latesttags[rev] = pdate, pdist + 1, ptag
107 latesttags[rev] = pdate, pdist + 1, ptag
108 return latesttags[rev]
108 return latesttags[rev]
109
109
110
110
111 def getlogcolumns():
111 def getlogcolumns():
112 """Return a dict of log column labels"""
112 """Return a dict of log column labels"""
113 _ = pycompat.identity # temporarily disable gettext
113 _ = pycompat.identity # temporarily disable gettext
114 # i18n: column positioning for "hg log"
114 # i18n: column positioning for "hg log"
115 columns = _(
115 columns = _(
116 b'bookmark: %s\n'
116 b'bookmark: %s\n'
117 b'branch: %s\n'
117 b'branch: %s\n'
118 b'changeset: %s\n'
118 b'changeset: %s\n'
119 b'copies: %s\n'
119 b'copies: %s\n'
120 b'date: %s\n'
120 b'date: %s\n'
121 b'extra: %s=%s\n'
121 b'extra: %s=%s\n'
122 b'files+: %s\n'
122 b'files+: %s\n'
123 b'files-: %s\n'
123 b'files-: %s\n'
124 b'files: %s\n'
124 b'files: %s\n'
125 b'instability: %s\n'
125 b'instability: %s\n'
126 b'manifest: %s\n'
126 b'manifest: %s\n'
127 b'obsolete: %s\n'
127 b'obsolete: %s\n'
128 b'parent: %s\n'
128 b'parent: %s\n'
129 b'phase: %s\n'
129 b'phase: %s\n'
130 b'summary: %s\n'
130 b'summary: %s\n'
131 b'tag: %s\n'
131 b'tag: %s\n'
132 b'user: %s\n'
132 b'user: %s\n'
133 )
133 )
134 return dict(
134 return dict(
135 zip(
135 zip(
136 [s.split(b':', 1)[0] for s in columns.splitlines()],
136 [s.split(b':', 1)[0] for s in columns.splitlines()],
137 i18n._(columns).splitlines(True),
137 i18n._(columns).splitlines(True),
138 )
138 )
139 )
139 )
140
140
141
141
142 # basic internal templates
142 # basic internal templates
143 _changeidtmpl = b'{rev}:{node|formatnode}'
143 _changeidtmpl = b'{rev}:{node|formatnode}'
144
144
145 # default templates internally used for rendering of lists
145 # default templates internally used for rendering of lists
146 defaulttempl = {
146 defaulttempl = {
147 b'parent': _changeidtmpl + b' ',
147 b'parent': _changeidtmpl + b' ',
148 b'manifest': _changeidtmpl,
148 b'manifest': _changeidtmpl,
149 b'file_copy': b'{name} ({source})',
149 b'file_copy': b'{name} ({source})',
150 b'envvar': b'{key}={value}',
150 b'envvar': b'{key}={value}',
151 b'extra': b'{key}={value|stringescape}',
151 b'extra': b'{key}={value|stringescape}',
152 }
152 }
153 # filecopy is preserved for compatibility reasons
153 # filecopy is preserved for compatibility reasons
154 defaulttempl[b'filecopy'] = defaulttempl[b'file_copy']
154 defaulttempl[b'filecopy'] = defaulttempl[b'file_copy']
155
155
156 # keywords are callables (see registrar.templatekeyword for details)
156 # keywords are callables (see registrar.templatekeyword for details)
157 keywords = {}
157 keywords = {}
158 templatekeyword = registrar.templatekeyword(keywords)
158 templatekeyword = registrar.templatekeyword(keywords)
159
159
160
160
161 @templatekeyword(b'author', requires={b'ctx'})
161 @templatekeyword(b'author', requires={b'ctx'})
162 def showauthor(context, mapping):
162 def showauthor(context, mapping):
163 """Alias for ``{user}``"""
163 """Alias for ``{user}``"""
164 return showuser(context, mapping)
164 return showuser(context, mapping)
165
165
166
166
167 @templatekeyword(b'bisect', requires={b'repo', b'ctx'})
167 @templatekeyword(b'bisect', requires={b'repo', b'ctx'})
168 def showbisect(context, mapping):
168 def showbisect(context, mapping):
169 """String. The changeset bisection status."""
169 """String. The changeset bisection status."""
170 repo = context.resource(mapping, b'repo')
170 repo = context.resource(mapping, b'repo')
171 ctx = context.resource(mapping, b'ctx')
171 ctx = context.resource(mapping, b'ctx')
172 return hbisect.label(repo, ctx.node())
172 return hbisect.label(repo, ctx.node())
173
173
174
174
175 @templatekeyword(b'branch', requires={b'ctx'})
175 @templatekeyword(b'branch', requires={b'ctx'})
176 def showbranch(context, mapping):
176 def showbranch(context, mapping):
177 """String. The name of the branch on which the changeset was
177 """String. The name of the branch on which the changeset was
178 committed.
178 committed.
179 """
179 """
180 ctx = context.resource(mapping, b'ctx')
180 ctx = context.resource(mapping, b'ctx')
181 return ctx.branch()
181 return ctx.branch()
182
182
183
183
184 @templatekeyword(b'branches', requires={b'ctx'})
184 @templatekeyword(b'branches', requires={b'ctx'})
185 def showbranches(context, mapping):
185 def showbranches(context, mapping):
186 """List of strings. The name of the branch on which the
186 """List of strings. The name of the branch on which the
187 changeset was committed. Will be empty if the branch name was
187 changeset was committed. Will be empty if the branch name was
188 default. (DEPRECATED)
188 default. (DEPRECATED)
189 """
189 """
190 ctx = context.resource(mapping, b'ctx')
190 ctx = context.resource(mapping, b'ctx')
191 branch = ctx.branch()
191 branch = ctx.branch()
192 if branch != b'default':
192 if branch != b'default':
193 return compatlist(
193 return compatlist(
194 context, mapping, b'branch', [branch], plural=b'branches'
194 context, mapping, b'branch', [branch], plural=b'branches'
195 )
195 )
196 return compatlist(context, mapping, b'branch', [], plural=b'branches')
196 return compatlist(context, mapping, b'branch', [], plural=b'branches')
197
197
198
198
199 @templatekeyword(b'bookmarks', requires={b'repo', b'ctx'})
199 @templatekeyword(b'bookmarks', requires={b'repo', b'ctx'})
200 def showbookmarks(context, mapping):
200 def showbookmarks(context, mapping):
201 """List of strings. Any bookmarks associated with the
201 """List of strings. Any bookmarks associated with the
202 changeset. Also sets 'active', the name of the active bookmark.
202 changeset. Also sets 'active', the name of the active bookmark.
203 """
203 """
204 repo = context.resource(mapping, b'repo')
204 repo = context.resource(mapping, b'repo')
205 ctx = context.resource(mapping, b'ctx')
205 ctx = context.resource(mapping, b'ctx')
206 bookmarks = ctx.bookmarks()
206 bookmarks = ctx.bookmarks()
207 active = repo._activebookmark
207 active = repo._activebookmark
208 makemap = lambda v: {b'bookmark': v, b'active': active, b'current': active}
208 makemap = lambda v: {b'bookmark': v, b'active': active, b'current': active}
209 f = _showcompatlist(context, mapping, b'bookmark', bookmarks)
209 f = _showcompatlist(context, mapping, b'bookmark', bookmarks)
210 return _hybrid(f, bookmarks, makemap, pycompat.identity)
210 return _hybrid(f, bookmarks, makemap, pycompat.identity)
211
211
212
212
213 @templatekeyword(b'children', requires={b'ctx'})
213 @templatekeyword(b'children', requires={b'ctx'})
214 def showchildren(context, mapping):
214 def showchildren(context, mapping):
215 """List of strings. The children of the changeset."""
215 """List of strings. The children of the changeset."""
216 ctx = context.resource(mapping, b'ctx')
216 ctx = context.resource(mapping, b'ctx')
217 childrevs = [b'%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
217 childrevs = [b'%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
218 return compatlist(
218 return compatlist(
219 context, mapping, b'children', childrevs, element=b'child'
219 context, mapping, b'children', childrevs, element=b'child'
220 )
220 )
221
221
222
222
223 # Deprecated, but kept alive for help generation a purpose.
223 # Deprecated, but kept alive for help generation a purpose.
224 @templatekeyword(b'currentbookmark', requires={b'repo', b'ctx'})
224 @templatekeyword(b'currentbookmark', requires={b'repo', b'ctx'})
225 def showcurrentbookmark(context, mapping):
225 def showcurrentbookmark(context, mapping):
226 """String. The active bookmark, if it is associated with the changeset.
226 """String. The active bookmark, if it is associated with the changeset.
227 (DEPRECATED)"""
227 (DEPRECATED)"""
228 return showactivebookmark(context, mapping)
228 return showactivebookmark(context, mapping)
229
229
230
230
231 @templatekeyword(b'activebookmark', requires={b'repo', b'ctx'})
231 @templatekeyword(b'activebookmark', requires={b'repo', b'ctx'})
232 def showactivebookmark(context, mapping):
232 def showactivebookmark(context, mapping):
233 """String. The active bookmark, if it is associated with the changeset."""
233 """String. The active bookmark, if it is associated with the changeset."""
234 repo = context.resource(mapping, b'repo')
234 repo = context.resource(mapping, b'repo')
235 ctx = context.resource(mapping, b'ctx')
235 ctx = context.resource(mapping, b'ctx')
236 active = repo._activebookmark
236 active = repo._activebookmark
237 if active and active in ctx.bookmarks():
237 if active and active in ctx.bookmarks():
238 return active
238 return active
239 return b''
239 return b''
240
240
241
241
242 @templatekeyword(b'date', requires={b'ctx'})
242 @templatekeyword(b'date', requires={b'ctx'})
243 def showdate(context, mapping):
243 def showdate(context, mapping):
244 """Date information. The date when the changeset was committed."""
244 """Date information. The date when the changeset was committed."""
245 ctx = context.resource(mapping, b'ctx')
245 ctx = context.resource(mapping, b'ctx')
246 # the default string format is '<float(unixtime)><tzoffset>' because
246 # the default string format is '<float(unixtime)><tzoffset>' because
247 # python-hglib splits date at decimal separator.
247 # python-hglib splits date at decimal separator.
248 return templateutil.date(ctx.date(), showfmt=b'%d.0%d')
248 return templateutil.date(ctx.date(), showfmt=b'%d.0%d')
249
249
250
250
251 @templatekeyword(b'desc', requires={b'ctx'})
251 @templatekeyword(b'desc', requires={b'ctx'})
252 def showdescription(context, mapping):
252 def showdescription(context, mapping):
253 """String. The text of the changeset description."""
253 """String. The text of the changeset description."""
254 ctx = context.resource(mapping, b'ctx')
254 ctx = context.resource(mapping, b'ctx')
255 s = ctx.description()
255 s = ctx.description()
256 if isinstance(s, encoding.localstr):
256 if isinstance(s, encoding.localstr):
257 # try hard to preserve utf-8 bytes
257 # try hard to preserve utf-8 bytes
258 return encoding.tolocal(encoding.fromlocal(s).strip())
258 return encoding.tolocal(encoding.fromlocal(s).strip())
259 elif isinstance(s, encoding.safelocalstr):
259 elif isinstance(s, encoding.safelocalstr):
260 return encoding.safelocalstr(s.strip())
260 return encoding.safelocalstr(s.strip())
261 else:
261 else:
262 return s.strip()
262 return s.strip()
263
263
264
264
265 @templatekeyword(b'diffstat', requires={b'ui', b'ctx'})
265 @templatekeyword(b'diffstat', requires={b'ui', b'ctx'})
266 def showdiffstat(context, mapping):
266 def showdiffstat(context, mapping):
267 """String. Statistics of changes with the following format:
267 """String. Statistics of changes with the following format:
268 "modified files: +added/-removed lines"
268 "modified files: +added/-removed lines"
269 """
269 """
270 ui = context.resource(mapping, b'ui')
270 ui = context.resource(mapping, b'ui')
271 ctx = context.resource(mapping, b'ctx')
271 ctx = context.resource(mapping, b'ctx')
272 diffopts = diffutil.diffallopts(ui, {b'noprefix': False})
272 diffopts = diffutil.diffallopts(ui, {b'noprefix': False})
273 diff = ctx.diff(opts=diffopts)
273 diff = ctx.diff(opts=diffopts)
274 stats = patch.diffstatdata(util.iterlines(diff))
274 stats = patch.diffstatdata(util.iterlines(diff))
275 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
275 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
276 return b'%d: +%d/-%d' % (len(stats), adds, removes)
276 return b'%d: +%d/-%d' % (len(stats), adds, removes)
277
277
278
278
279 @templatekeyword(b'envvars', requires={b'ui'})
279 @templatekeyword(b'envvars', requires={b'ui'})
280 def showenvvars(context, mapping):
280 def showenvvars(context, mapping):
281 """A dictionary of environment variables. (EXPERIMENTAL)"""
281 """A dictionary of environment variables. (EXPERIMENTAL)"""
282 ui = context.resource(mapping, b'ui')
282 ui = context.resource(mapping, b'ui')
283 env = ui.exportableenviron()
283 env = ui.exportableenviron()
284 env = util.sortdict((k, env[k]) for k in sorted(env))
284 env = util.sortdict((k, env[k]) for k in sorted(env))
285 return compatdict(context, mapping, b'envvar', env, plural=b'envvars')
285 return compatdict(context, mapping, b'envvar', env, plural=b'envvars')
286
286
287
287
288 @templatekeyword(b'extras', requires={b'ctx'})
288 @templatekeyword(b'extras', requires={b'ctx'})
289 def showextras(context, mapping):
289 def showextras(context, mapping):
290 """List of dicts with key, value entries of the 'extras'
290 """List of dicts with key, value entries of the 'extras'
291 field of this changeset."""
291 field of this changeset."""
292 ctx = context.resource(mapping, b'ctx')
292 ctx = context.resource(mapping, b'ctx')
293 extras = ctx.extra()
293 extras = ctx.extra()
294 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
294 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
295 makemap = lambda k: {b'key': k, b'value': extras[k]}
295 makemap = lambda k: {b'key': k, b'value': extras[k]}
296 c = [makemap(k) for k in extras]
296 c = [makemap(k) for k in extras]
297 f = _showcompatlist(context, mapping, b'extra', c, plural=b'extras')
297 f = _showcompatlist(context, mapping, b'extra', c, plural=b'extras')
298 return _hybrid(
298 return _hybrid(
299 f,
299 f,
300 extras,
300 extras,
301 makemap,
301 makemap,
302 lambda k: b'%s=%s' % (k, stringutil.escapestr(extras[k])),
302 lambda k: b'%s=%s' % (k, stringutil.escapestr(extras[k])),
303 )
303 )
304
304
305
305
306 @templatekeyword(b'_fast_rank', requires={b'ctx'})
306 @templatekeyword(b'_fast_rank', requires={b'ctx'})
307 def fast_rank(context, mapping):
307 def fast_rank(context, mapping):
308 """the rank of a changeset if cached
308 """the rank of a changeset if cached
309
309
310 The rank of a revision is the size of the sub-graph it defines as a head.
310 The rank of a revision is the size of the sub-graph it defines as a head.
311 Equivalently, the rank of a revision `r` is the size of the set
311 Equivalently, the rank of a revision `r` is the size of the set
312 `ancestors(r)`, `r` included.
312 `ancestors(r)`, `r` included.
313 """
313 """
314 ctx = context.resource(mapping, b'ctx')
314 ctx = context.resource(mapping, b'ctx')
315 rank = ctx.fast_rank()
315 rank = ctx.fast_rank()
316 if rank is None:
316 if rank is None:
317 return None
317 return None
318 return b"%d" % rank
318 return b"%d" % rank
319
319
320
320
321 def _getfilestatus(context, mapping, listall=False):
321 def _getfilestatus(context, mapping, listall=False):
322 ctx = context.resource(mapping, b'ctx')
322 ctx = context.resource(mapping, b'ctx')
323 revcache = context.resource(mapping, b'revcache')
323 revcache = context.resource(mapping, b'revcache')
324 if b'filestatus' not in revcache or revcache[b'filestatusall'] < listall:
324 if b'filestatus' not in revcache or revcache[b'filestatusall'] < listall:
325 stat = ctx.p1().status(
325 stat = ctx.p1().status(
326 ctx, listignored=listall, listclean=listall, listunknown=listall
326 ctx, listignored=listall, listclean=listall, listunknown=listall
327 )
327 )
328 revcache[b'filestatus'] = stat
328 revcache[b'filestatus'] = stat
329 revcache[b'filestatusall'] = listall
329 revcache[b'filestatusall'] = listall
330 return revcache[b'filestatus']
330 return revcache[b'filestatus']
331
331
332
332
333 def _getfilestatusmap(context, mapping, listall=False):
333 def _getfilestatusmap(context, mapping, listall=False):
334 revcache = context.resource(mapping, b'revcache')
334 revcache = context.resource(mapping, b'revcache')
335 if b'filestatusmap' not in revcache or revcache[b'filestatusall'] < listall:
335 if b'filestatusmap' not in revcache or revcache[b'filestatusall'] < listall:
336 stat = _getfilestatus(context, mapping, listall=listall)
336 stat = _getfilestatus(context, mapping, listall=listall)
337 revcache[b'filestatusmap'] = statmap = {}
337 revcache[b'filestatusmap'] = statmap = {}
338 for char, files in zip(pycompat.iterbytestr(b'MAR!?IC'), stat):
338 for char, files in zip(pycompat.iterbytestr(b'MAR!?IC'), stat):
339 statmap.update((f, char) for f in files)
339 statmap.update((f, char) for f in files)
340 return revcache[b'filestatusmap'] # {path: statchar}
340 return revcache[b'filestatusmap'] # {path: statchar}
341
341
342
342
343 @templatekeyword(
343 @templatekeyword(
344 b'file_copies', requires={b'repo', b'ctx', b'cache', b'revcache'}
344 b'file_copies', requires={b'repo', b'ctx', b'cache', b'revcache'}
345 )
345 )
346 def showfilecopies(context, mapping):
346 def showfilecopies(context, mapping):
347 """List of strings. Files copied in this changeset with
347 """List of strings. Files copied in this changeset with
348 their sources.
348 their sources.
349 """
349 """
350 repo = context.resource(mapping, b'repo')
350 repo = context.resource(mapping, b'repo')
351 ctx = context.resource(mapping, b'ctx')
351 ctx = context.resource(mapping, b'ctx')
352 cache = context.resource(mapping, b'cache')
352 cache = context.resource(mapping, b'cache')
353 copies = context.resource(mapping, b'revcache').get(b'copies')
353 copies = context.resource(mapping, b'revcache').get(b'copies')
354 if copies is None:
354 if copies is None:
355 if b'getcopies' not in cache:
355 if b'getcopies' not in cache:
356 cache[b'getcopies'] = scmutil.getcopiesfn(repo)
356 cache[b'getcopies'] = scmutil.getcopiesfn(repo)
357 getcopies = cache[b'getcopies']
357 getcopies = cache[b'getcopies']
358 copies = getcopies(ctx)
358 copies = getcopies(ctx)
359 return templateutil.compatfilecopiesdict(
359 return templateutil.compatfilecopiesdict(
360 context, mapping, b'file_copy', copies
360 context, mapping, b'file_copy', copies
361 )
361 )
362
362
363
363
364 # showfilecopiesswitch() displays file copies only if copy records are
364 # showfilecopiesswitch() displays file copies only if copy records are
365 # provided before calling the templater, usually with a --copies
365 # provided before calling the templater, usually with a --copies
366 # command line switch.
366 # command line switch.
367 @templatekeyword(b'file_copies_switch', requires={b'revcache'})
367 @templatekeyword(b'file_copies_switch', requires={b'revcache'})
368 def showfilecopiesswitch(context, mapping):
368 def showfilecopiesswitch(context, mapping):
369 """List of strings. Like "file_copies" but displayed
369 """List of strings. Like "file_copies" but displayed
370 only if the --copied switch is set.
370 only if the --copied switch is set.
371 """
371 """
372 copies = context.resource(mapping, b'revcache').get(b'copies') or []
372 copies = context.resource(mapping, b'revcache').get(b'copies') or []
373 return templateutil.compatfilecopiesdict(
373 return templateutil.compatfilecopiesdict(
374 context, mapping, b'file_copy', copies
374 context, mapping, b'file_copy', copies
375 )
375 )
376
376
377
377
378 @templatekeyword(b'file_adds', requires={b'ctx', b'revcache'})
378 @templatekeyword(b'file_adds', requires={b'ctx', b'revcache'})
379 def showfileadds(context, mapping):
379 def showfileadds(context, mapping):
380 """List of strings. Files added by this changeset."""
380 """List of strings. Files added by this changeset."""
381 ctx = context.resource(mapping, b'ctx')
381 ctx = context.resource(mapping, b'ctx')
382 return templateutil.compatfileslist(
382 return templateutil.compatfileslist(
383 context, mapping, b'file_add', ctx.filesadded()
383 context, mapping, b'file_add', ctx.filesadded()
384 )
384 )
385
385
386
386
387 @templatekeyword(b'file_dels', requires={b'ctx', b'revcache'})
387 @templatekeyword(b'file_dels', requires={b'ctx', b'revcache'})
388 def showfiledels(context, mapping):
388 def showfiledels(context, mapping):
389 """List of strings. Files removed by this changeset."""
389 """List of strings. Files removed by this changeset."""
390 ctx = context.resource(mapping, b'ctx')
390 ctx = context.resource(mapping, b'ctx')
391 return templateutil.compatfileslist(
391 return templateutil.compatfileslist(
392 context, mapping, b'file_del', ctx.filesremoved()
392 context, mapping, b'file_del', ctx.filesremoved()
393 )
393 )
394
394
395
395
396 @templatekeyword(b'file_mods', requires={b'ctx', b'revcache'})
396 @templatekeyword(b'file_mods', requires={b'ctx', b'revcache'})
397 def showfilemods(context, mapping):
397 def showfilemods(context, mapping):
398 """List of strings. Files modified by this changeset."""
398 """List of strings. Files modified by this changeset."""
399 ctx = context.resource(mapping, b'ctx')
399 ctx = context.resource(mapping, b'ctx')
400 return templateutil.compatfileslist(
400 return templateutil.compatfileslist(
401 context, mapping, b'file_mod', ctx.filesmodified()
401 context, mapping, b'file_mod', ctx.filesmodified()
402 )
402 )
403
403
404
404
405 @templatekeyword(b'files', requires={b'ctx'})
405 @templatekeyword(b'files', requires={b'ctx'})
406 def showfiles(context, mapping):
406 def showfiles(context, mapping):
407 """List of strings. All files modified, added, or removed by this
407 """List of strings. All files modified, added, or removed by this
408 changeset.
408 changeset.
409 """
409 """
410 ctx = context.resource(mapping, b'ctx')
410 ctx = context.resource(mapping, b'ctx')
411 return templateutil.compatfileslist(context, mapping, b'file', ctx.files())
411 return templateutil.compatfileslist(context, mapping, b'file', ctx.files())
412
412
413
413
414 @templatekeyword(b'graphnode', requires={b'repo', b'ctx', b'cache'})
414 @templatekeyword(b'graphnode', requires={b'repo', b'ctx', b'cache'})
415 def showgraphnode(context, mapping):
415 def showgraphnode(context, mapping):
416 """String. The character representing the changeset node in an ASCII
416 """String. The character representing the changeset node in an ASCII
417 revision graph."""
417 revision graph."""
418 repo = context.resource(mapping, b'repo')
418 repo = context.resource(mapping, b'repo')
419 ctx = context.resource(mapping, b'ctx')
419 ctx = context.resource(mapping, b'ctx')
420 cache = context.resource(mapping, b'cache')
420 cache = context.resource(mapping, b'cache')
421 return getgraphnode(repo, ctx, cache)
421 return getgraphnode(repo, ctx, cache)
422
422
423
423
424 def getgraphnode(repo, ctx, cache):
424 def getgraphnode(repo, ctx, cache):
425 return getgraphnodecurrent(repo, ctx, cache) or getgraphnodesymbol(ctx)
425 return getgraphnodecurrent(repo, ctx, cache) or getgraphnodesymbol(ctx)
426
426
427
427
428 def getgraphnodecurrent(repo, ctx, cache):
428 def getgraphnodecurrent(repo, ctx, cache):
429 wpnodes = repo.dirstate.parents()
429 wpnodes = repo.dirstate.parents()
430 if wpnodes[1] == repo.nullid:
430 if wpnodes[1] == repo.nullid:
431 wpnodes = wpnodes[:1]
431 wpnodes = wpnodes[:1]
432 if ctx.node() in wpnodes:
432 if ctx.node() in wpnodes:
433 return b'@'
433 return b'@'
434 else:
434 else:
435 merge_nodes = cache.get(b'merge_nodes')
435 merge_nodes = cache.get(b'merge_nodes')
436 if merge_nodes is None:
436 if merge_nodes is None:
437 from . import mergestate as mergestatemod
437 from . import mergestate as mergestatemod
438
438
439 mergestate = mergestatemod.mergestate.read(repo)
439 mergestate = mergestatemod.mergestate.read(repo)
440 if mergestate.unresolvedcount():
440 if mergestate.unresolvedcount():
441 merge_nodes = (mergestate.local, mergestate.other)
441 merge_nodes = (mergestate.local, mergestate.other)
442 else:
442 else:
443 merge_nodes = ()
443 merge_nodes = ()
444 cache[b'merge_nodes'] = merge_nodes
444 cache[b'merge_nodes'] = merge_nodes
445
445
446 if ctx.node() in merge_nodes:
446 if ctx.node() in merge_nodes:
447 return b'%'
447 return b'%'
448 return b''
448 return b''
449
449
450
450
451 def getgraphnodesymbol(ctx):
451 def getgraphnodesymbol(ctx):
452 if ctx.obsolete():
452 if ctx.obsolete():
453 return b'x'
453 return b'x'
454 elif ctx.isunstable():
454 elif ctx.isunstable():
455 return b'*'
455 return b'*'
456 elif ctx.closesbranch():
456 elif ctx.closesbranch():
457 return b'_'
457 return b'_'
458 else:
458 else:
459 return b'o'
459 return b'o'
460
460
461
461
462 @templatekeyword(b'graphwidth', requires=())
462 @templatekeyword(b'graphwidth', requires=())
463 def showgraphwidth(context, mapping):
463 def showgraphwidth(context, mapping):
464 """Integer. The width of the graph drawn by 'log --graph' or zero."""
464 """Integer. The width of the graph drawn by 'log --graph' or zero."""
465 # just hosts documentation; should be overridden by template mapping
465 # just hosts documentation; should be overridden by template mapping
466 return 0
466 return 0
467
467
468
468
469 @templatekeyword(b'index', requires=())
469 @templatekeyword(b'index', requires=())
470 def showindex(context, mapping):
470 def showindex(context, mapping):
471 """Integer. The current iteration of the loop. (0 indexed)"""
471 """Integer. The current iteration of the loop. (0 indexed)"""
472 # just hosts documentation; should be overridden by template mapping
472 # just hosts documentation; should be overridden by template mapping
473 raise error.Abort(_(b"can't use index in this context"))
473 raise error.Abort(_(b"can't use index in this context"))
474
474
475
475
476 @templatekeyword(b'latesttag', requires={b'repo', b'ctx', b'cache'})
476 @templatekeyword(b'latesttag', requires={b'repo', b'ctx', b'cache'})
477 def showlatesttag(context, mapping):
477 def showlatesttag(context, mapping):
478 """List of strings. The global tags on the most recent globally
478 """List of strings. The global tags on the most recent globally
479 tagged ancestor of this changeset. If no such tags exist, the list
479 tagged ancestor of this changeset. If no such tags exist, the list
480 consists of the single string "null".
480 consists of the single string "null".
481 """
481 """
482 return showlatesttags(context, mapping, None)
482 return showlatesttags(context, mapping, None)
483
483
484
484
485 def showlatesttags(context, mapping, pattern):
485 def showlatesttags(context, mapping, pattern):
486 """helper method for the latesttag keyword and function"""
486 """helper method for the latesttag keyword and function"""
487 latesttags = getlatesttags(context, mapping, pattern)
487 latesttags = getlatesttags(context, mapping, pattern)
488
488
489 # latesttag[0] is an implementation detail for sorting csets on different
489 # latesttag[0] is an implementation detail for sorting csets on different
490 # branches in a stable manner- it is the date the tagged cset was created,
490 # branches in a stable manner- it is the date the tagged cset was created,
491 # not the date the tag was created. Therefore it isn't made visible here.
491 # not the date the tag was created. Therefore it isn't made visible here.
492 makemap = lambda v: {
492 makemap = lambda v: {
493 b'changes': _showchangessincetag,
493 b'changes': _showchangessincetag,
494 b'distance': latesttags[1],
494 b'distance': latesttags[1],
495 b'latesttag': v, # BC with {latesttag % '{latesttag}'}
495 b'latesttag': v, # BC with {latesttag % '{latesttag}'}
496 b'tag': v,
496 b'tag': v,
497 }
497 }
498
498
499 tags = latesttags[2]
499 tags = latesttags[2]
500 f = _showcompatlist(context, mapping, b'latesttag', tags, separator=b':')
500 f = _showcompatlist(context, mapping, b'latesttag', tags, separator=b':')
501 return _hybrid(f, tags, makemap, pycompat.identity)
501 return _hybrid(f, tags, makemap, pycompat.identity)
502
502
503
503
504 @templatekeyword(b'latesttagdistance', requires={b'repo', b'ctx', b'cache'})
504 @templatekeyword(b'latesttagdistance', requires={b'repo', b'ctx', b'cache'})
505 def showlatesttagdistance(context, mapping):
505 def showlatesttagdistance(context, mapping):
506 """Integer. Longest path to the latest tag."""
506 """Integer. Longest path to the latest tag."""
507 return getlatesttags(context, mapping)[1]
507 return getlatesttags(context, mapping)[1]
508
508
509
509
510 @templatekeyword(b'changessincelatesttag', requires={b'repo', b'ctx', b'cache'})
510 @templatekeyword(b'changessincelatesttag', requires={b'repo', b'ctx', b'cache'})
511 def showchangessincelatesttag(context, mapping):
511 def showchangessincelatesttag(context, mapping):
512 """Integer. All ancestors not in the latest tag."""
512 """Integer. All ancestors not in the latest tag."""
513 tag = getlatesttags(context, mapping)[2][0]
513 tag = getlatesttags(context, mapping)[2][0]
514 mapping = context.overlaymap(mapping, {b'tag': tag})
514 mapping = context.overlaymap(mapping, {b'tag': tag})
515 return _showchangessincetag(context, mapping)
515 return _showchangessincetag(context, mapping)
516
516
517
517
518 def _showchangessincetag(context, mapping):
518 def _showchangessincetag(context, mapping):
519 repo = context.resource(mapping, b'repo')
519 repo = context.resource(mapping, b'repo')
520 ctx = context.resource(mapping, b'ctx')
520 ctx = context.resource(mapping, b'ctx')
521 offset = 0
521 offset = 0
522 revs = [ctx.rev()]
522 revs = [ctx.rev()]
523 tag = context.symbol(mapping, b'tag')
523 tag = context.symbol(mapping, b'tag')
524
524
525 # The only() revset doesn't currently support wdir()
525 # The only() revset doesn't currently support wdir()
526 if ctx.rev() is None:
526 if ctx.rev() is None:
527 offset = 1
527 offset = 1
528 revs = [p.rev() for p in ctx.parents()]
528 revs = [p.rev() for p in ctx.parents()]
529
529
530 return len(repo.revs(b'only(%ld, %s)', revs, tag)) + offset
530 return len(repo.revs(b'only(%ld, %s)', revs, tag)) + offset
531
531
532
532
533 # teach templater latesttags.changes is switched to (context, mapping) API
533 # teach templater latesttags.changes is switched to (context, mapping) API
534 _showchangessincetag._requires = {b'repo', b'ctx'}
534 _showchangessincetag._requires = {b'repo', b'ctx'}
535
535
536
536
537 @templatekeyword(b'manifest', requires={b'repo', b'ctx'})
537 @templatekeyword(b'manifest', requires={b'repo', b'ctx'})
538 def showmanifest(context, mapping):
538 def showmanifest(context, mapping):
539 repo = context.resource(mapping, b'repo')
539 repo = context.resource(mapping, b'repo')
540 ctx = context.resource(mapping, b'ctx')
540 ctx = context.resource(mapping, b'ctx')
541 mnode = ctx.manifestnode()
541 mnode = ctx.manifestnode()
542 if mnode is None:
542 if mnode is None:
543 mnode = repo.nodeconstants.wdirid
543 mnode = repo.nodeconstants.wdirid
544 mrev = wdirrev
544 mrev = wdirrev
545 mhex = repo.nodeconstants.wdirhex
545 mhex = repo.nodeconstants.wdirhex
546 else:
546 else:
547 mrev = repo.manifestlog.rev(mnode)
547 mrev = repo.manifestlog.rev(mnode)
548 mhex = hex(mnode)
548 mhex = hex(mnode)
549 mapping = context.overlaymap(mapping, {b'rev': mrev, b'node': mhex})
549 mapping = context.overlaymap(mapping, {b'rev': mrev, b'node': mhex})
550 f = context.process(b'manifest', mapping)
550 f = context.process(b'manifest', mapping)
551 return templateutil.hybriditem(
551 return templateutil.hybriditem(
552 f, None, f, lambda x: {b'rev': mrev, b'node': mhex}
552 f, None, f, lambda x: {b'rev': mrev, b'node': mhex}
553 )
553 )
554
554
555
555
556 @templatekeyword(b'obsfate', requires={b'ui', b'repo', b'ctx'})
556 @templatekeyword(b'obsfate', requires={b'ui', b'repo', b'ctx'})
557 def showobsfate(context, mapping):
557 def showobsfate(context, mapping):
558 # this function returns a list containing pre-formatted obsfate strings.
558 # this function returns a list containing pre-formatted obsfate strings.
559 #
559 #
560 # This function will be replaced by templates fragments when we will have
560 # This function will be replaced by templates fragments when we will have
561 # the verbosity templatekw available.
561 # the verbosity templatekw available.
562 succsandmarkers = showsuccsandmarkers(context, mapping)
562 succsandmarkers = showsuccsandmarkers(context, mapping)
563
563
564 ui = context.resource(mapping, b'ui')
564 ui = context.resource(mapping, b'ui')
565 repo = context.resource(mapping, b'repo')
565 repo = context.resource(mapping, b'repo')
566 values = []
566 values = []
567
567
568 for x in succsandmarkers.tovalue(context, mapping):
568 for x in succsandmarkers.tovalue(context, mapping):
569 v = obsutil.obsfateprinter(
569 v = obsutil.obsfateprinter(
570 ui, repo, x[b'successors'], x[b'markers'], scmutil.formatchangeid
570 ui, repo, x[b'successors'], x[b'markers'], scmutil.formatchangeid
571 )
571 )
572 values.append(v)
572 values.append(v)
573
573
574 return compatlist(context, mapping, b"fate", values)
574 return compatlist(context, mapping, b"fate", values)
575
575
576
576
577 def shownames(context, mapping, namespace):
577 def shownames(context, mapping, namespace):
578 """helper method to generate a template keyword for a namespace"""
578 """helper method to generate a template keyword for a namespace"""
579 repo = context.resource(mapping, b'repo')
579 repo = context.resource(mapping, b'repo')
580 ctx = context.resource(mapping, b'ctx')
580 ctx = context.resource(mapping, b'ctx')
581 ns = repo.names.get(namespace)
581 ns = repo.names.get(namespace)
582 if ns is None:
582 if ns is None:
583 # namespaces.addnamespace() registers new template keyword, but
583 # namespaces.addnamespace() registers new template keyword, but
584 # the registered namespace might not exist in the current repo.
584 # the registered namespace might not exist in the current repo.
585 return
585 return
586 names = ns.names(repo, ctx.node())
586 names = ns.names(repo, ctx.node())
587 return compatlist(
587 return compatlist(
588 context, mapping, ns.templatename, names, plural=namespace
588 context, mapping, ns.templatename, names, plural=namespace
589 )
589 )
590
590
591
591
592 @templatekeyword(b'namespaces', requires={b'repo', b'ctx'})
592 @templatekeyword(b'namespaces', requires={b'repo', b'ctx'})
593 def shownamespaces(context, mapping):
593 def shownamespaces(context, mapping):
594 """Dict of lists. Names attached to this changeset per
594 """Dict of lists. Names attached to this changeset per
595 namespace."""
595 namespace."""
596 repo = context.resource(mapping, b'repo')
596 repo = context.resource(mapping, b'repo')
597 ctx = context.resource(mapping, b'ctx')
597 ctx = context.resource(mapping, b'ctx')
598
598
599 namespaces = util.sortdict()
599 namespaces = util.sortdict()
600
600
601 def makensmapfn(ns):
601 def makensmapfn(ns):
602 # 'name' for iterating over namespaces, templatename for local reference
602 # 'name' for iterating over namespaces, templatename for local reference
603 return lambda v: {b'name': v, ns.templatename: v}
603 return lambda v: {b'name': v, ns.templatename: v}
604
604
605 for k, ns in repo.names.items():
605 for k, ns in repo.names.items():
606 names = ns.names(repo, ctx.node())
606 names = ns.names(repo, ctx.node())
607 f = _showcompatlist(context, mapping, b'name', names)
607 f = _showcompatlist(context, mapping, b'name', names)
608 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
608 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
609
609
610 f = _showcompatlist(context, mapping, b'namespace', list(namespaces))
610 f = _showcompatlist(context, mapping, b'namespace', list(namespaces))
611
611
612 def makemap(ns):
612 def makemap(ns):
613 return {
613 return {
614 b'namespace': ns,
614 b'namespace': ns,
615 b'names': namespaces[ns],
615 b'names': namespaces[ns],
616 b'builtin': repo.names[ns].builtin,
616 b'builtin': repo.names[ns].builtin,
617 b'colorname': repo.names[ns].colorname,
617 b'colorname': repo.names[ns].colorname,
618 }
618 }
619
619
620 return _hybrid(f, namespaces, makemap, pycompat.identity)
620 return _hybrid(f, namespaces, makemap, pycompat.identity)
621
621
622
622
623 @templatekeyword(b'negrev', requires={b'repo', b'ctx'})
623 @templatekeyword(b'negrev', requires={b'repo', b'ctx'})
624 def shownegrev(context, mapping):
624 def shownegrev(context, mapping):
625 """Integer. The repository-local changeset negative revision number,
625 """Integer. The repository-local changeset negative revision number,
626 which counts in the opposite direction."""
626 which counts in the opposite direction."""
627 ctx = context.resource(mapping, b'ctx')
627 ctx = context.resource(mapping, b'ctx')
628 rev = ctx.rev()
628 rev = ctx.rev()
629 if rev is None or rev < 0: # wdir() or nullrev?
629 if rev is None or rev < 0: # wdir() or nullrev?
630 return None
630 return None
631 repo = context.resource(mapping, b'repo')
631 repo = context.resource(mapping, b'repo')
632 return rev - len(repo)
632 return rev - len(repo)
633
633
634
634
635 @templatekeyword(b'node', requires={b'ctx'})
635 @templatekeyword(b'node', requires={b'ctx'})
636 def shownode(context, mapping):
636 def shownode(context, mapping):
637 """String. The changeset identification hash, as a 40 hexadecimal
637 """String. The changeset identification hash, as a 40 hexadecimal
638 digit string.
638 digit string.
639 """
639 """
640 ctx = context.resource(mapping, b'ctx')
640 ctx = context.resource(mapping, b'ctx')
641 return ctx.hex()
641 return ctx.hex()
642
642
643
643
644 @templatekeyword(b'obsolete', requires={b'ctx'})
644 @templatekeyword(b'obsolete', requires={b'ctx'})
645 def showobsolete(context, mapping):
645 def showobsolete(context, mapping):
646 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
646 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
647 ctx = context.resource(mapping, b'ctx')
647 ctx = context.resource(mapping, b'ctx')
648 if ctx.obsolete():
648 if ctx.obsolete():
649 return b'obsolete'
649 return b'obsolete'
650 return b''
650 return b''
651
651
652
652
653 @templatekeyword(b'onelinesummary', requires={b'ui', b'ctx'})
653 @templatekeyword(b'onelinesummary', requires={b'ui', b'ctx'})
654 def showonelinesummary(context, mapping):
654 def showonelinesummary(context, mapping):
655 """String. A one-line summary for the ctx (not including trailing newline).
655 """String. A one-line summary for the ctx (not including trailing newline).
656 The default template be overridden in command-templates.oneline-summary."""
656 The default template be overridden in command-templates.oneline-summary."""
657 # Avoid cycle:
657 # Avoid cycle:
658 # mercurial.cmdutil -> mercurial.templatekw -> mercurial.cmdutil
658 # mercurial.cmdutil -> mercurial.templatekw -> mercurial.cmdutil
659 from . import cmdutil
659 from . import cmdutil
660
660
661 ui = context.resource(mapping, b'ui')
661 ui = context.resource(mapping, b'ui')
662 ctx = context.resource(mapping, b'ctx')
662 ctx = context.resource(mapping, b'ctx')
663 return cmdutil.format_changeset_summary(ui, ctx)
663 return cmdutil.format_changeset_summary(ui, ctx)
664
664
665
665
666 @templatekeyword(b'path', requires={b'fctx'})
666 @templatekeyword(b'path', requires={b'fctx'})
667 def showpath(context, mapping):
667 def showpath(context, mapping):
668 """String. Repository-absolute path of the current file. (EXPERIMENTAL)"""
668 """String. Repository-absolute path of the current file. (EXPERIMENTAL)"""
669 fctx = context.resource(mapping, b'fctx')
669 fctx = context.resource(mapping, b'fctx')
670 return fctx.path()
670 return fctx.path()
671
671
672
672
673 @templatekeyword(b'peerurls', requires={b'repo'})
673 @templatekeyword(b'peerurls', requires={b'repo'})
674 def showpeerurls(context, mapping):
674 def showpeerurls(context, mapping):
675 """A dictionary of repository locations defined in the [paths] section
675 """A dictionary of repository locations defined in the [paths] section
676 of your configuration file."""
676 of your configuration file."""
677 repo = context.resource(mapping, b'repo')
677 repo = context.resource(mapping, b'repo')
678 # see commands.paths() for naming of dictionary keys
678 # see commands.paths() for naming of dictionary keys
679 paths = repo.ui.paths
679 paths = repo.ui.paths
680 all_paths = urlutil.list_paths(repo.ui)
680 all_paths = urlutil.list_paths(repo.ui)
681 urls = util.sortdict((k, p.rawloc) for k, p in all_paths)
681 urls = util.sortdict((k, p.rawloc) for k, p in all_paths)
682
682
683 def makemap(k):
683 def makemap(k):
684 ps = paths[k]
684 ps = paths[k]
685 d = {b'name': k}
685 d = {b'name': k}
686 if len(ps) == 1:
686 if len(ps) == 1:
687 d[b'url'] = ps[0].rawloc
687 d[b'url'] = ps[0].rawloc
688 sub_opts = pycompat.iteritems(ps[0].suboptions)
688 sub_opts = ps[0].suboptions.items()
689 sub_opts = util.sortdict(sorted(sub_opts))
689 sub_opts = util.sortdict(sorted(sub_opts))
690 d.update(sub_opts)
690 d.update(sub_opts)
691 path_dict = util.sortdict()
691 path_dict = util.sortdict()
692 for p in ps:
692 for p in ps:
693 sub_opts = util.sortdict(sorted(p.suboptions.items()))
693 sub_opts = util.sortdict(sorted(p.suboptions.items()))
694 path_dict[b'url'] = p.rawloc
694 path_dict[b'url'] = p.rawloc
695 path_dict.update(sub_opts)
695 path_dict.update(sub_opts)
696 d[b'urls'] = [path_dict]
696 d[b'urls'] = [path_dict]
697 return d
697 return d
698
698
699 def format_one(k):
699 def format_one(k):
700 return b'%s=%s' % (k, urls[k])
700 return b'%s=%s' % (k, urls[k])
701
701
702 return _hybrid(None, urls, makemap, format_one)
702 return _hybrid(None, urls, makemap, format_one)
703
703
704
704
705 @templatekeyword(b"predecessors", requires={b'repo', b'ctx'})
705 @templatekeyword(b"predecessors", requires={b'repo', b'ctx'})
706 def showpredecessors(context, mapping):
706 def showpredecessors(context, mapping):
707 """Returns the list of the closest visible predecessors. (EXPERIMENTAL)"""
707 """Returns the list of the closest visible predecessors. (EXPERIMENTAL)"""
708 repo = context.resource(mapping, b'repo')
708 repo = context.resource(mapping, b'repo')
709 ctx = context.resource(mapping, b'ctx')
709 ctx = context.resource(mapping, b'ctx')
710 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
710 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
711 predecessors = pycompat.maplist(hex, predecessors)
711 predecessors = pycompat.maplist(hex, predecessors)
712
712
713 return _hybrid(
713 return _hybrid(
714 None,
714 None,
715 predecessors,
715 predecessors,
716 lambda x: {b'ctx': repo[x]},
716 lambda x: {b'ctx': repo[x]},
717 lambda x: scmutil.formatchangeid(repo[x]),
717 lambda x: scmutil.formatchangeid(repo[x]),
718 )
718 )
719
719
720
720
721 @templatekeyword(b'reporoot', requires={b'repo'})
721 @templatekeyword(b'reporoot', requires={b'repo'})
722 def showreporoot(context, mapping):
722 def showreporoot(context, mapping):
723 """String. The root directory of the current repository."""
723 """String. The root directory of the current repository."""
724 repo = context.resource(mapping, b'repo')
724 repo = context.resource(mapping, b'repo')
725 return repo.root
725 return repo.root
726
726
727
727
728 @templatekeyword(b'size', requires={b'fctx'})
728 @templatekeyword(b'size', requires={b'fctx'})
729 def showsize(context, mapping):
729 def showsize(context, mapping):
730 """Integer. Size of the current file in bytes. (EXPERIMENTAL)"""
730 """Integer. Size of the current file in bytes. (EXPERIMENTAL)"""
731 fctx = context.resource(mapping, b'fctx')
731 fctx = context.resource(mapping, b'fctx')
732 return fctx.size()
732 return fctx.size()
733
733
734
734
735 # requires 'fctx' to denote {status} depends on (ctx, path) pair
735 # requires 'fctx' to denote {status} depends on (ctx, path) pair
736 @templatekeyword(b'status', requires={b'ctx', b'fctx', b'revcache'})
736 @templatekeyword(b'status', requires={b'ctx', b'fctx', b'revcache'})
737 def showstatus(context, mapping):
737 def showstatus(context, mapping):
738 """String. Status code of the current file. (EXPERIMENTAL)"""
738 """String. Status code of the current file. (EXPERIMENTAL)"""
739 path = templateutil.runsymbol(context, mapping, b'path')
739 path = templateutil.runsymbol(context, mapping, b'path')
740 path = templateutil.stringify(context, mapping, path)
740 path = templateutil.stringify(context, mapping, path)
741 if not path:
741 if not path:
742 return
742 return
743 statmap = _getfilestatusmap(context, mapping)
743 statmap = _getfilestatusmap(context, mapping)
744 if path not in statmap:
744 if path not in statmap:
745 statmap = _getfilestatusmap(context, mapping, listall=True)
745 statmap = _getfilestatusmap(context, mapping, listall=True)
746 return statmap.get(path)
746 return statmap.get(path)
747
747
748
748
749 @templatekeyword(b"successorssets", requires={b'repo', b'ctx'})
749 @templatekeyword(b"successorssets", requires={b'repo', b'ctx'})
750 def showsuccessorssets(context, mapping):
750 def showsuccessorssets(context, mapping):
751 """Returns a string of sets of successors for a changectx. Format used
751 """Returns a string of sets of successors for a changectx. Format used
752 is: [ctx1, ctx2], [ctx3] if ctx has been split into ctx1 and ctx2
752 is: [ctx1, ctx2], [ctx3] if ctx has been split into ctx1 and ctx2
753 while also diverged into ctx3. (EXPERIMENTAL)"""
753 while also diverged into ctx3. (EXPERIMENTAL)"""
754 repo = context.resource(mapping, b'repo')
754 repo = context.resource(mapping, b'repo')
755 ctx = context.resource(mapping, b'ctx')
755 ctx = context.resource(mapping, b'ctx')
756 data = []
756 data = []
757
757
758 if ctx.obsolete():
758 if ctx.obsolete():
759 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
759 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
760 ssets = [[hex(n) for n in ss] for ss in ssets]
760 ssets = [[hex(n) for n in ss] for ss in ssets]
761
761
762 for ss in ssets:
762 for ss in ssets:
763 h = _hybrid(
763 h = _hybrid(
764 None,
764 None,
765 ss,
765 ss,
766 lambda x: {b'ctx': repo[x]},
766 lambda x: {b'ctx': repo[x]},
767 lambda x: scmutil.formatchangeid(repo[x]),
767 lambda x: scmutil.formatchangeid(repo[x]),
768 )
768 )
769 data.append(h)
769 data.append(h)
770
770
771 # Format the successorssets
771 # Format the successorssets
772 def render(d):
772 def render(d):
773 return templateutil.stringify(context, mapping, d)
773 return templateutil.stringify(context, mapping, d)
774
774
775 def gen(data):
775 def gen(data):
776 yield b"; ".join(render(d) for d in data)
776 yield b"; ".join(render(d) for d in data)
777
777
778 return _hybrid(
778 return _hybrid(
779 gen(data), data, lambda x: {b'successorset': x}, pycompat.identity
779 gen(data), data, lambda x: {b'successorset': x}, pycompat.identity
780 )
780 )
781
781
782
782
783 @templatekeyword(b"succsandmarkers", requires={b'repo', b'ctx'})
783 @templatekeyword(b"succsandmarkers", requires={b'repo', b'ctx'})
784 def showsuccsandmarkers(context, mapping):
784 def showsuccsandmarkers(context, mapping):
785 """Returns a list of dict for each final successor of ctx. The dict
785 """Returns a list of dict for each final successor of ctx. The dict
786 contains successors node id in "successors" keys and the list of
786 contains successors node id in "successors" keys and the list of
787 obs-markers from ctx to the set of successors in "markers".
787 obs-markers from ctx to the set of successors in "markers".
788 (EXPERIMENTAL)
788 (EXPERIMENTAL)
789 """
789 """
790 repo = context.resource(mapping, b'repo')
790 repo = context.resource(mapping, b'repo')
791 ctx = context.resource(mapping, b'ctx')
791 ctx = context.resource(mapping, b'ctx')
792
792
793 values = obsutil.successorsandmarkers(repo, ctx)
793 values = obsutil.successorsandmarkers(repo, ctx)
794
794
795 if values is None:
795 if values is None:
796 values = []
796 values = []
797
797
798 # Format successors and markers to avoid exposing binary to templates
798 # Format successors and markers to avoid exposing binary to templates
799 data = []
799 data = []
800 for i in values:
800 for i in values:
801 # Format successors
801 # Format successors
802 successors = i[b'successors']
802 successors = i[b'successors']
803
803
804 successors = [hex(n) for n in successors]
804 successors = [hex(n) for n in successors]
805 successors = _hybrid(
805 successors = _hybrid(
806 None,
806 None,
807 successors,
807 successors,
808 lambda x: {b'ctx': repo[x]},
808 lambda x: {b'ctx': repo[x]},
809 lambda x: scmutil.formatchangeid(repo[x]),
809 lambda x: scmutil.formatchangeid(repo[x]),
810 )
810 )
811
811
812 # Format markers
812 # Format markers
813 finalmarkers = []
813 finalmarkers = []
814 for m in i[b'markers']:
814 for m in i[b'markers']:
815 hexprec = hex(m[0])
815 hexprec = hex(m[0])
816 hexsucs = tuple(hex(n) for n in m[1])
816 hexsucs = tuple(hex(n) for n in m[1])
817 hexparents = None
817 hexparents = None
818 if m[5] is not None:
818 if m[5] is not None:
819 hexparents = tuple(hex(n) for n in m[5])
819 hexparents = tuple(hex(n) for n in m[5])
820 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
820 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
821 finalmarkers.append(newmarker)
821 finalmarkers.append(newmarker)
822
822
823 data.append({b'successors': successors, b'markers': finalmarkers})
823 data.append({b'successors': successors, b'markers': finalmarkers})
824
824
825 return templateutil.mappinglist(data)
825 return templateutil.mappinglist(data)
826
826
827
827
828 @templatekeyword(b'p1', requires={b'ctx'})
828 @templatekeyword(b'p1', requires={b'ctx'})
829 def showp1(context, mapping):
829 def showp1(context, mapping):
830 """Changeset. The changeset's first parent. ``{p1.rev}`` for the revision
830 """Changeset. The changeset's first parent. ``{p1.rev}`` for the revision
831 number, and ``{p1.node}`` for the identification hash."""
831 number, and ``{p1.node}`` for the identification hash."""
832 ctx = context.resource(mapping, b'ctx')
832 ctx = context.resource(mapping, b'ctx')
833 return templateutil.mappingdict({b'ctx': ctx.p1()}, tmpl=_changeidtmpl)
833 return templateutil.mappingdict({b'ctx': ctx.p1()}, tmpl=_changeidtmpl)
834
834
835
835
836 @templatekeyword(b'p2', requires={b'ctx'})
836 @templatekeyword(b'p2', requires={b'ctx'})
837 def showp2(context, mapping):
837 def showp2(context, mapping):
838 """Changeset. The changeset's second parent. ``{p2.rev}`` for the revision
838 """Changeset. The changeset's second parent. ``{p2.rev}`` for the revision
839 number, and ``{p2.node}`` for the identification hash."""
839 number, and ``{p2.node}`` for the identification hash."""
840 ctx = context.resource(mapping, b'ctx')
840 ctx = context.resource(mapping, b'ctx')
841 return templateutil.mappingdict({b'ctx': ctx.p2()}, tmpl=_changeidtmpl)
841 return templateutil.mappingdict({b'ctx': ctx.p2()}, tmpl=_changeidtmpl)
842
842
843
843
844 @templatekeyword(b'p1rev', requires={b'ctx'})
844 @templatekeyword(b'p1rev', requires={b'ctx'})
845 def showp1rev(context, mapping):
845 def showp1rev(context, mapping):
846 """Integer. The repository-local revision number of the changeset's
846 """Integer. The repository-local revision number of the changeset's
847 first parent, or -1 if the changeset has no parents. (DEPRECATED)"""
847 first parent, or -1 if the changeset has no parents. (DEPRECATED)"""
848 ctx = context.resource(mapping, b'ctx')
848 ctx = context.resource(mapping, b'ctx')
849 return ctx.p1().rev()
849 return ctx.p1().rev()
850
850
851
851
852 @templatekeyword(b'p2rev', requires={b'ctx'})
852 @templatekeyword(b'p2rev', requires={b'ctx'})
853 def showp2rev(context, mapping):
853 def showp2rev(context, mapping):
854 """Integer. The repository-local revision number of the changeset's
854 """Integer. The repository-local revision number of the changeset's
855 second parent, or -1 if the changeset has no second parent. (DEPRECATED)"""
855 second parent, or -1 if the changeset has no second parent. (DEPRECATED)"""
856 ctx = context.resource(mapping, b'ctx')
856 ctx = context.resource(mapping, b'ctx')
857 return ctx.p2().rev()
857 return ctx.p2().rev()
858
858
859
859
860 @templatekeyword(b'p1node', requires={b'ctx'})
860 @templatekeyword(b'p1node', requires={b'ctx'})
861 def showp1node(context, mapping):
861 def showp1node(context, mapping):
862 """String. The identification hash of the changeset's first parent,
862 """String. The identification hash of the changeset's first parent,
863 as a 40 digit hexadecimal string. If the changeset has no parents, all
863 as a 40 digit hexadecimal string. If the changeset has no parents, all
864 digits are 0. (DEPRECATED)"""
864 digits are 0. (DEPRECATED)"""
865 ctx = context.resource(mapping, b'ctx')
865 ctx = context.resource(mapping, b'ctx')
866 return ctx.p1().hex()
866 return ctx.p1().hex()
867
867
868
868
869 @templatekeyword(b'p2node', requires={b'ctx'})
869 @templatekeyword(b'p2node', requires={b'ctx'})
870 def showp2node(context, mapping):
870 def showp2node(context, mapping):
871 """String. The identification hash of the changeset's second
871 """String. The identification hash of the changeset's second
872 parent, as a 40 digit hexadecimal string. If the changeset has no second
872 parent, as a 40 digit hexadecimal string. If the changeset has no second
873 parent, all digits are 0. (DEPRECATED)"""
873 parent, all digits are 0. (DEPRECATED)"""
874 ctx = context.resource(mapping, b'ctx')
874 ctx = context.resource(mapping, b'ctx')
875 return ctx.p2().hex()
875 return ctx.p2().hex()
876
876
877
877
878 @templatekeyword(b'parents', requires={b'repo', b'ctx'})
878 @templatekeyword(b'parents', requires={b'repo', b'ctx'})
879 def showparents(context, mapping):
879 def showparents(context, mapping):
880 """List of strings. The parents of the changeset in "rev:node"
880 """List of strings. The parents of the changeset in "rev:node"
881 format. If the changeset has only one "natural" parent (the predecessor
881 format. If the changeset has only one "natural" parent (the predecessor
882 revision) nothing is shown."""
882 revision) nothing is shown."""
883 repo = context.resource(mapping, b'repo')
883 repo = context.resource(mapping, b'repo')
884 ctx = context.resource(mapping, b'ctx')
884 ctx = context.resource(mapping, b'ctx')
885 pctxs = scmutil.meaningfulparents(repo, ctx)
885 pctxs = scmutil.meaningfulparents(repo, ctx)
886 prevs = [p.rev() for p in pctxs]
886 prevs = [p.rev() for p in pctxs]
887 parents = [
887 parents = [
888 [(b'rev', p.rev()), (b'node', p.hex()), (b'phase', p.phasestr())]
888 [(b'rev', p.rev()), (b'node', p.hex()), (b'phase', p.phasestr())]
889 for p in pctxs
889 for p in pctxs
890 ]
890 ]
891 f = _showcompatlist(context, mapping, b'parent', parents)
891 f = _showcompatlist(context, mapping, b'parent', parents)
892 return _hybrid(
892 return _hybrid(
893 f,
893 f,
894 prevs,
894 prevs,
895 lambda x: {b'ctx': repo[x]},
895 lambda x: {b'ctx': repo[x]},
896 lambda x: scmutil.formatchangeid(repo[x]),
896 lambda x: scmutil.formatchangeid(repo[x]),
897 keytype=int,
897 keytype=int,
898 )
898 )
899
899
900
900
901 @templatekeyword(b'phase', requires={b'ctx'})
901 @templatekeyword(b'phase', requires={b'ctx'})
902 def showphase(context, mapping):
902 def showphase(context, mapping):
903 """String. The changeset phase name."""
903 """String. The changeset phase name."""
904 ctx = context.resource(mapping, b'ctx')
904 ctx = context.resource(mapping, b'ctx')
905 return ctx.phasestr()
905 return ctx.phasestr()
906
906
907
907
908 @templatekeyword(b'phaseidx', requires={b'ctx'})
908 @templatekeyword(b'phaseidx', requires={b'ctx'})
909 def showphaseidx(context, mapping):
909 def showphaseidx(context, mapping):
910 """Integer. The changeset phase index. (ADVANCED)"""
910 """Integer. The changeset phase index. (ADVANCED)"""
911 ctx = context.resource(mapping, b'ctx')
911 ctx = context.resource(mapping, b'ctx')
912 return ctx.phase()
912 return ctx.phase()
913
913
914
914
915 @templatekeyword(b'rev', requires={b'ctx'})
915 @templatekeyword(b'rev', requires={b'ctx'})
916 def showrev(context, mapping):
916 def showrev(context, mapping):
917 """Integer. The repository-local changeset revision number."""
917 """Integer. The repository-local changeset revision number."""
918 ctx = context.resource(mapping, b'ctx')
918 ctx = context.resource(mapping, b'ctx')
919 return scmutil.intrev(ctx)
919 return scmutil.intrev(ctx)
920
920
921
921
922 @templatekeyword(b'subrepos', requires={b'ctx'})
922 @templatekeyword(b'subrepos', requires={b'ctx'})
923 def showsubrepos(context, mapping):
923 def showsubrepos(context, mapping):
924 """List of strings. Updated subrepositories in the changeset."""
924 """List of strings. Updated subrepositories in the changeset."""
925 ctx = context.resource(mapping, b'ctx')
925 ctx = context.resource(mapping, b'ctx')
926 substate = ctx.substate
926 substate = ctx.substate
927 if not substate:
927 if not substate:
928 return compatlist(context, mapping, b'subrepo', [])
928 return compatlist(context, mapping, b'subrepo', [])
929 psubstate = ctx.p1().substate or {}
929 psubstate = ctx.p1().substate or {}
930 subrepos = []
930 subrepos = []
931 for sub in substate:
931 for sub in substate:
932 if sub not in psubstate or substate[sub] != psubstate[sub]:
932 if sub not in psubstate or substate[sub] != psubstate[sub]:
933 subrepos.append(sub) # modified or newly added in ctx
933 subrepos.append(sub) # modified or newly added in ctx
934 for sub in psubstate:
934 for sub in psubstate:
935 if sub not in substate:
935 if sub not in substate:
936 subrepos.append(sub) # removed in ctx
936 subrepos.append(sub) # removed in ctx
937 return compatlist(context, mapping, b'subrepo', sorted(subrepos))
937 return compatlist(context, mapping, b'subrepo', sorted(subrepos))
938
938
939
939
940 # don't remove "showtags" definition, even though namespaces will put
940 # don't remove "showtags" definition, even though namespaces will put
941 # a helper function for "tags" keyword into "keywords" map automatically,
941 # a helper function for "tags" keyword into "keywords" map automatically,
942 # because online help text is built without namespaces initialization
942 # because online help text is built without namespaces initialization
943 @templatekeyword(b'tags', requires={b'repo', b'ctx'})
943 @templatekeyword(b'tags', requires={b'repo', b'ctx'})
944 def showtags(context, mapping):
944 def showtags(context, mapping):
945 """List of strings. Any tags associated with the changeset."""
945 """List of strings. Any tags associated with the changeset."""
946 return shownames(context, mapping, b'tags')
946 return shownames(context, mapping, b'tags')
947
947
948
948
949 @templatekeyword(b'termwidth', requires={b'ui'})
949 @templatekeyword(b'termwidth', requires={b'ui'})
950 def showtermwidth(context, mapping):
950 def showtermwidth(context, mapping):
951 """Integer. The width of the current terminal."""
951 """Integer. The width of the current terminal."""
952 ui = context.resource(mapping, b'ui')
952 ui = context.resource(mapping, b'ui')
953 return ui.termwidth()
953 return ui.termwidth()
954
954
955
955
956 @templatekeyword(b'user', requires={b'ctx'})
956 @templatekeyword(b'user', requires={b'ctx'})
957 def showuser(context, mapping):
957 def showuser(context, mapping):
958 """String. The unmodified author of the changeset."""
958 """String. The unmodified author of the changeset."""
959 ctx = context.resource(mapping, b'ctx')
959 ctx = context.resource(mapping, b'ctx')
960 return ctx.user()
960 return ctx.user()
961
961
962
962
963 @templatekeyword(b'instabilities', requires={b'ctx'})
963 @templatekeyword(b'instabilities', requires={b'ctx'})
964 def showinstabilities(context, mapping):
964 def showinstabilities(context, mapping):
965 """List of strings. Evolution instabilities affecting the changeset.
965 """List of strings. Evolution instabilities affecting the changeset.
966 (EXPERIMENTAL)
966 (EXPERIMENTAL)
967 """
967 """
968 ctx = context.resource(mapping, b'ctx')
968 ctx = context.resource(mapping, b'ctx')
969 return compatlist(
969 return compatlist(
970 context,
970 context,
971 mapping,
971 mapping,
972 b'instability',
972 b'instability',
973 ctx.instabilities(),
973 ctx.instabilities(),
974 plural=b'instabilities',
974 plural=b'instabilities',
975 )
975 )
976
976
977
977
978 @templatekeyword(b'verbosity', requires={b'ui'})
978 @templatekeyword(b'verbosity', requires={b'ui'})
979 def showverbosity(context, mapping):
979 def showverbosity(context, mapping):
980 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
980 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
981 or ''."""
981 or ''."""
982 ui = context.resource(mapping, b'ui')
982 ui = context.resource(mapping, b'ui')
983 # see logcmdutil.changesettemplater for priority of these flags
983 # see logcmdutil.changesettemplater for priority of these flags
984 if ui.debugflag:
984 if ui.debugflag:
985 return b'debug'
985 return b'debug'
986 elif ui.quiet:
986 elif ui.quiet:
987 return b'quiet'
987 return b'quiet'
988 elif ui.verbose:
988 elif ui.verbose:
989 return b'verbose'
989 return b'verbose'
990 return b''
990 return b''
991
991
992
992
993 @templatekeyword(b'whyunstable', requires={b'repo', b'ctx'})
993 @templatekeyword(b'whyunstable', requires={b'repo', b'ctx'})
994 def showwhyunstable(context, mapping):
994 def showwhyunstable(context, mapping):
995 """List of dicts explaining all instabilities of a changeset.
995 """List of dicts explaining all instabilities of a changeset.
996 (EXPERIMENTAL)
996 (EXPERIMENTAL)
997 """
997 """
998 repo = context.resource(mapping, b'repo')
998 repo = context.resource(mapping, b'repo')
999 ctx = context.resource(mapping, b'ctx')
999 ctx = context.resource(mapping, b'ctx')
1000
1000
1001 def formatnode(ctx):
1001 def formatnode(ctx):
1002 return b'%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr())
1002 return b'%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr())
1003
1003
1004 entries = obsutil.whyunstable(repo, ctx)
1004 entries = obsutil.whyunstable(repo, ctx)
1005
1005
1006 for entry in entries:
1006 for entry in entries:
1007 if entry.get(b'divergentnodes'):
1007 if entry.get(b'divergentnodes'):
1008 dnodes = entry[b'divergentnodes']
1008 dnodes = entry[b'divergentnodes']
1009 dnhybrid = _hybrid(
1009 dnhybrid = _hybrid(
1010 None,
1010 None,
1011 [dnode.hex() for dnode in dnodes],
1011 [dnode.hex() for dnode in dnodes],
1012 lambda x: {b'ctx': repo[x]},
1012 lambda x: {b'ctx': repo[x]},
1013 lambda x: formatnode(repo[x]),
1013 lambda x: formatnode(repo[x]),
1014 )
1014 )
1015 entry[b'divergentnodes'] = dnhybrid
1015 entry[b'divergentnodes'] = dnhybrid
1016
1016
1017 tmpl = (
1017 tmpl = (
1018 b'{instability}:{if(divergentnodes, " ")}{divergentnodes} '
1018 b'{instability}:{if(divergentnodes, " ")}{divergentnodes} '
1019 b'{reason} {node|short}'
1019 b'{reason} {node|short}'
1020 )
1020 )
1021 return templateutil.mappinglist(entries, tmpl=tmpl, sep=b'\n')
1021 return templateutil.mappinglist(entries, tmpl=tmpl, sep=b'\n')
1022
1022
1023
1023
1024 def loadkeyword(ui, extname, registrarobj):
1024 def loadkeyword(ui, extname, registrarobj):
1025 """Load template keyword from specified registrarobj"""
1025 """Load template keyword from specified registrarobj"""
1026 for name, func in registrarobj._table.items():
1026 for name, func in registrarobj._table.items():
1027 keywords[name] = func
1027 keywords[name] = func
1028
1028
1029
1029
1030 # tell hggettext to extract docstrings from these functions:
1030 # tell hggettext to extract docstrings from these functions:
1031 i18nfunctions = keywords.values()
1031 i18nfunctions = keywords.values()
General Comments 0
You need to be logged in to leave comments. Login now