##// END OF EJS Templates
templatekw: mark _showlist() as deprecated (API)...
Yuya Nishihara -
r37089:d3f7930a default
parent child Browse files
Show More
@@ -1,798 +1,802 b''
1 # templatekw.py - common changeset template keywords
1 # templatekw.py - common changeset template keywords
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2009 Matt Mackall <mpm@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 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from .i18n import _
10 from .i18n import _
11 from .node import (
11 from .node import (
12 hex,
12 hex,
13 nullid,
13 nullid,
14 )
14 )
15
15
16 from . import (
16 from . import (
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
29
30 _hybrid = templateutil.hybrid
30 _hybrid = templateutil.hybrid
31 _mappable = templateutil.mappable
31 _mappable = templateutil.mappable
32 hybriddict = templateutil.hybriddict
32 hybriddict = templateutil.hybriddict
33 hybridlist = templateutil.hybridlist
33 hybridlist = templateutil.hybridlist
34 compatdict = templateutil.compatdict
34 compatdict = templateutil.compatdict
35 compatlist = templateutil.compatlist
35 compatlist = templateutil.compatlist
36 _showcompatlist = templateutil._showcompatlist
36 _showcompatlist = templateutil._showcompatlist
37
37
38 def _showlist(name, values, templ, mapping, plural=None, separator=' '):
38 def _showlist(name, values, templ, mapping, plural=None, separator=' '):
39 ui = mapping.get('ui')
40 if ui:
41 ui.deprecwarn("templatekw._showlist() is deprecated, use "
42 "templateutil._showcompatlist()", '4.6')
39 context = templ # this is actually a template context, not a templater
43 context = templ # this is actually a template context, not a templater
40 return _showcompatlist(context, mapping, name, values, plural, separator)
44 return _showcompatlist(context, mapping, name, values, plural, separator)
41
45
42 def showdict(name, data, mapping, plural=None, key='key', value='value',
46 def showdict(name, data, mapping, plural=None, key='key', value='value',
43 fmt=None, separator=' '):
47 fmt=None, separator=' '):
44 ui = mapping.get('ui')
48 ui = mapping.get('ui')
45 if ui:
49 if ui:
46 ui.deprecwarn("templatekw.showdict() is deprecated, use "
50 ui.deprecwarn("templatekw.showdict() is deprecated, use "
47 "templateutil.compatdict()", '4.6')
51 "templateutil.compatdict()", '4.6')
48 c = [{key: k, value: v} for k, v in data.iteritems()]
52 c = [{key: k, value: v} for k, v in data.iteritems()]
49 f = _showlist(name, c, mapping['templ'], mapping, plural, separator)
53 f = _showlist(name, c, mapping['templ'], mapping, plural, separator)
50 return hybriddict(data, key=key, value=value, fmt=fmt, gen=f)
54 return hybriddict(data, key=key, value=value, fmt=fmt, gen=f)
51
55
52 def showlist(name, values, mapping, plural=None, element=None, separator=' '):
56 def showlist(name, values, mapping, plural=None, element=None, separator=' '):
53 ui = mapping.get('ui')
57 ui = mapping.get('ui')
54 if ui:
58 if ui:
55 ui.deprecwarn("templatekw.showlist() is deprecated, use "
59 ui.deprecwarn("templatekw.showlist() is deprecated, use "
56 "templateutil.compatlist()", '4.6')
60 "templateutil.compatlist()", '4.6')
57 if not element:
61 if not element:
58 element = name
62 element = name
59 f = _showlist(name, values, mapping['templ'], mapping, plural, separator)
63 f = _showlist(name, values, mapping['templ'], mapping, plural, separator)
60 return hybridlist(values, name=element, gen=f)
64 return hybridlist(values, name=element, gen=f)
61
65
62 def getlatesttags(context, mapping, pattern=None):
66 def getlatesttags(context, mapping, pattern=None):
63 '''return date, distance and name for the latest tag of rev'''
67 '''return date, distance and name for the latest tag of rev'''
64 repo = context.resource(mapping, 'repo')
68 repo = context.resource(mapping, 'repo')
65 ctx = context.resource(mapping, 'ctx')
69 ctx = context.resource(mapping, 'ctx')
66 cache = context.resource(mapping, 'cache')
70 cache = context.resource(mapping, 'cache')
67
71
68 cachename = 'latesttags'
72 cachename = 'latesttags'
69 if pattern is not None:
73 if pattern is not None:
70 cachename += '-' + pattern
74 cachename += '-' + pattern
71 match = util.stringmatcher(pattern)[2]
75 match = util.stringmatcher(pattern)[2]
72 else:
76 else:
73 match = util.always
77 match = util.always
74
78
75 if cachename not in cache:
79 if cachename not in cache:
76 # Cache mapping from rev to a tuple with tag date, tag
80 # Cache mapping from rev to a tuple with tag date, tag
77 # distance and tag name
81 # distance and tag name
78 cache[cachename] = {-1: (0, 0, ['null'])}
82 cache[cachename] = {-1: (0, 0, ['null'])}
79 latesttags = cache[cachename]
83 latesttags = cache[cachename]
80
84
81 rev = ctx.rev()
85 rev = ctx.rev()
82 todo = [rev]
86 todo = [rev]
83 while todo:
87 while todo:
84 rev = todo.pop()
88 rev = todo.pop()
85 if rev in latesttags:
89 if rev in latesttags:
86 continue
90 continue
87 ctx = repo[rev]
91 ctx = repo[rev]
88 tags = [t for t in ctx.tags()
92 tags = [t for t in ctx.tags()
89 if (repo.tagtype(t) and repo.tagtype(t) != 'local'
93 if (repo.tagtype(t) and repo.tagtype(t) != 'local'
90 and match(t))]
94 and match(t))]
91 if tags:
95 if tags:
92 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
96 latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
93 continue
97 continue
94 try:
98 try:
95 ptags = [latesttags[p.rev()] for p in ctx.parents()]
99 ptags = [latesttags[p.rev()] for p in ctx.parents()]
96 if len(ptags) > 1:
100 if len(ptags) > 1:
97 if ptags[0][2] == ptags[1][2]:
101 if ptags[0][2] == ptags[1][2]:
98 # The tuples are laid out so the right one can be found by
102 # The tuples are laid out so the right one can be found by
99 # comparison in this case.
103 # comparison in this case.
100 pdate, pdist, ptag = max(ptags)
104 pdate, pdist, ptag = max(ptags)
101 else:
105 else:
102 def key(x):
106 def key(x):
103 changessincetag = len(repo.revs('only(%d, %s)',
107 changessincetag = len(repo.revs('only(%d, %s)',
104 ctx.rev(), x[2][0]))
108 ctx.rev(), x[2][0]))
105 # Smallest number of changes since tag wins. Date is
109 # Smallest number of changes since tag wins. Date is
106 # used as tiebreaker.
110 # used as tiebreaker.
107 return [-changessincetag, x[0]]
111 return [-changessincetag, x[0]]
108 pdate, pdist, ptag = max(ptags, key=key)
112 pdate, pdist, ptag = max(ptags, key=key)
109 else:
113 else:
110 pdate, pdist, ptag = ptags[0]
114 pdate, pdist, ptag = ptags[0]
111 except KeyError:
115 except KeyError:
112 # Cache miss - recurse
116 # Cache miss - recurse
113 todo.append(rev)
117 todo.append(rev)
114 todo.extend(p.rev() for p in ctx.parents())
118 todo.extend(p.rev() for p in ctx.parents())
115 continue
119 continue
116 latesttags[rev] = pdate, pdist + 1, ptag
120 latesttags[rev] = pdate, pdist + 1, ptag
117 return latesttags[rev]
121 return latesttags[rev]
118
122
119 def getrenamedfn(repo, endrev=None):
123 def getrenamedfn(repo, endrev=None):
120 rcache = {}
124 rcache = {}
121 if endrev is None:
125 if endrev is None:
122 endrev = len(repo)
126 endrev = len(repo)
123
127
124 def getrenamed(fn, rev):
128 def getrenamed(fn, rev):
125 '''looks up all renames for a file (up to endrev) the first
129 '''looks up all renames for a file (up to endrev) the first
126 time the file is given. It indexes on the changerev and only
130 time the file is given. It indexes on the changerev and only
127 parses the manifest if linkrev != changerev.
131 parses the manifest if linkrev != changerev.
128 Returns rename info for fn at changerev rev.'''
132 Returns rename info for fn at changerev rev.'''
129 if fn not in rcache:
133 if fn not in rcache:
130 rcache[fn] = {}
134 rcache[fn] = {}
131 fl = repo.file(fn)
135 fl = repo.file(fn)
132 for i in fl:
136 for i in fl:
133 lr = fl.linkrev(i)
137 lr = fl.linkrev(i)
134 renamed = fl.renamed(fl.node(i))
138 renamed = fl.renamed(fl.node(i))
135 rcache[fn][lr] = renamed
139 rcache[fn][lr] = renamed
136 if lr >= endrev:
140 if lr >= endrev:
137 break
141 break
138 if rev in rcache[fn]:
142 if rev in rcache[fn]:
139 return rcache[fn][rev]
143 return rcache[fn][rev]
140
144
141 # If linkrev != rev (i.e. rev not found in rcache) fallback to
145 # If linkrev != rev (i.e. rev not found in rcache) fallback to
142 # filectx logic.
146 # filectx logic.
143 try:
147 try:
144 return repo[rev][fn].renamed()
148 return repo[rev][fn].renamed()
145 except error.LookupError:
149 except error.LookupError:
146 return None
150 return None
147
151
148 return getrenamed
152 return getrenamed
149
153
150 def getlogcolumns():
154 def getlogcolumns():
151 """Return a dict of log column labels"""
155 """Return a dict of log column labels"""
152 _ = pycompat.identity # temporarily disable gettext
156 _ = pycompat.identity # temporarily disable gettext
153 # i18n: column positioning for "hg log"
157 # i18n: column positioning for "hg log"
154 columns = _('bookmark: %s\n'
158 columns = _('bookmark: %s\n'
155 'branch: %s\n'
159 'branch: %s\n'
156 'changeset: %s\n'
160 'changeset: %s\n'
157 'copies: %s\n'
161 'copies: %s\n'
158 'date: %s\n'
162 'date: %s\n'
159 'extra: %s=%s\n'
163 'extra: %s=%s\n'
160 'files+: %s\n'
164 'files+: %s\n'
161 'files-: %s\n'
165 'files-: %s\n'
162 'files: %s\n'
166 'files: %s\n'
163 'instability: %s\n'
167 'instability: %s\n'
164 'manifest: %s\n'
168 'manifest: %s\n'
165 'obsolete: %s\n'
169 'obsolete: %s\n'
166 'parent: %s\n'
170 'parent: %s\n'
167 'phase: %s\n'
171 'phase: %s\n'
168 'summary: %s\n'
172 'summary: %s\n'
169 'tag: %s\n'
173 'tag: %s\n'
170 'user: %s\n')
174 'user: %s\n')
171 return dict(zip([s.split(':', 1)[0] for s in columns.splitlines()],
175 return dict(zip([s.split(':', 1)[0] for s in columns.splitlines()],
172 i18n._(columns).splitlines(True)))
176 i18n._(columns).splitlines(True)))
173
177
174 # default templates internally used for rendering of lists
178 # default templates internally used for rendering of lists
175 defaulttempl = {
179 defaulttempl = {
176 'parent': '{rev}:{node|formatnode} ',
180 'parent': '{rev}:{node|formatnode} ',
177 'manifest': '{rev}:{node|formatnode}',
181 'manifest': '{rev}:{node|formatnode}',
178 'file_copy': '{name} ({source})',
182 'file_copy': '{name} ({source})',
179 'envvar': '{key}={value}',
183 'envvar': '{key}={value}',
180 'extra': '{key}={value|stringescape}'
184 'extra': '{key}={value|stringescape}'
181 }
185 }
182 # filecopy is preserved for compatibility reasons
186 # filecopy is preserved for compatibility reasons
183 defaulttempl['filecopy'] = defaulttempl['file_copy']
187 defaulttempl['filecopy'] = defaulttempl['file_copy']
184
188
185 # keywords are callables (see registrar.templatekeyword for details)
189 # keywords are callables (see registrar.templatekeyword for details)
186 keywords = {}
190 keywords = {}
187 templatekeyword = registrar.templatekeyword(keywords)
191 templatekeyword = registrar.templatekeyword(keywords)
188
192
189 @templatekeyword('author', requires={'ctx'})
193 @templatekeyword('author', requires={'ctx'})
190 def showauthor(context, mapping):
194 def showauthor(context, mapping):
191 """String. The unmodified author of the changeset."""
195 """String. The unmodified author of the changeset."""
192 ctx = context.resource(mapping, 'ctx')
196 ctx = context.resource(mapping, 'ctx')
193 return ctx.user()
197 return ctx.user()
194
198
195 @templatekeyword('bisect', requires={'repo', 'ctx'})
199 @templatekeyword('bisect', requires={'repo', 'ctx'})
196 def showbisect(context, mapping):
200 def showbisect(context, mapping):
197 """String. The changeset bisection status."""
201 """String. The changeset bisection status."""
198 repo = context.resource(mapping, 'repo')
202 repo = context.resource(mapping, 'repo')
199 ctx = context.resource(mapping, 'ctx')
203 ctx = context.resource(mapping, 'ctx')
200 return hbisect.label(repo, ctx.node())
204 return hbisect.label(repo, ctx.node())
201
205
202 @templatekeyword('branch', requires={'ctx'})
206 @templatekeyword('branch', requires={'ctx'})
203 def showbranch(context, mapping):
207 def showbranch(context, mapping):
204 """String. The name of the branch on which the changeset was
208 """String. The name of the branch on which the changeset was
205 committed.
209 committed.
206 """
210 """
207 ctx = context.resource(mapping, 'ctx')
211 ctx = context.resource(mapping, 'ctx')
208 return ctx.branch()
212 return ctx.branch()
209
213
210 @templatekeyword('branches', requires={'ctx'})
214 @templatekeyword('branches', requires={'ctx'})
211 def showbranches(context, mapping):
215 def showbranches(context, mapping):
212 """List of strings. The name of the branch on which the
216 """List of strings. The name of the branch on which the
213 changeset was committed. Will be empty if the branch name was
217 changeset was committed. Will be empty if the branch name was
214 default. (DEPRECATED)
218 default. (DEPRECATED)
215 """
219 """
216 ctx = context.resource(mapping, 'ctx')
220 ctx = context.resource(mapping, 'ctx')
217 branch = ctx.branch()
221 branch = ctx.branch()
218 if branch != 'default':
222 if branch != 'default':
219 return compatlist(context, mapping, 'branch', [branch],
223 return compatlist(context, mapping, 'branch', [branch],
220 plural='branches')
224 plural='branches')
221 return compatlist(context, mapping, 'branch', [], plural='branches')
225 return compatlist(context, mapping, 'branch', [], plural='branches')
222
226
223 @templatekeyword('bookmarks', requires={'repo', 'ctx'})
227 @templatekeyword('bookmarks', requires={'repo', 'ctx'})
224 def showbookmarks(context, mapping):
228 def showbookmarks(context, mapping):
225 """List of strings. Any bookmarks associated with the
229 """List of strings. Any bookmarks associated with the
226 changeset. Also sets 'active', the name of the active bookmark.
230 changeset. Also sets 'active', the name of the active bookmark.
227 """
231 """
228 repo = context.resource(mapping, 'repo')
232 repo = context.resource(mapping, 'repo')
229 ctx = context.resource(mapping, 'ctx')
233 ctx = context.resource(mapping, 'ctx')
230 bookmarks = ctx.bookmarks()
234 bookmarks = ctx.bookmarks()
231 active = repo._activebookmark
235 active = repo._activebookmark
232 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
236 makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
233 f = _showcompatlist(context, mapping, 'bookmark', bookmarks)
237 f = _showcompatlist(context, mapping, 'bookmark', bookmarks)
234 return _hybrid(f, bookmarks, makemap, pycompat.identity)
238 return _hybrid(f, bookmarks, makemap, pycompat.identity)
235
239
236 @templatekeyword('children', requires={'ctx'})
240 @templatekeyword('children', requires={'ctx'})
237 def showchildren(context, mapping):
241 def showchildren(context, mapping):
238 """List of strings. The children of the changeset."""
242 """List of strings. The children of the changeset."""
239 ctx = context.resource(mapping, 'ctx')
243 ctx = context.resource(mapping, 'ctx')
240 childrevs = ['%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
244 childrevs = ['%d:%s' % (cctx.rev(), cctx) for cctx in ctx.children()]
241 return compatlist(context, mapping, 'children', childrevs, element='child')
245 return compatlist(context, mapping, 'children', childrevs, element='child')
242
246
243 # Deprecated, but kept alive for help generation a purpose.
247 # Deprecated, but kept alive for help generation a purpose.
244 @templatekeyword('currentbookmark', requires={'repo', 'ctx'})
248 @templatekeyword('currentbookmark', requires={'repo', 'ctx'})
245 def showcurrentbookmark(context, mapping):
249 def showcurrentbookmark(context, mapping):
246 """String. The active bookmark, if it is associated with the changeset.
250 """String. The active bookmark, if it is associated with the changeset.
247 (DEPRECATED)"""
251 (DEPRECATED)"""
248 return showactivebookmark(context, mapping)
252 return showactivebookmark(context, mapping)
249
253
250 @templatekeyword('activebookmark', requires={'repo', 'ctx'})
254 @templatekeyword('activebookmark', requires={'repo', 'ctx'})
251 def showactivebookmark(context, mapping):
255 def showactivebookmark(context, mapping):
252 """String. The active bookmark, if it is associated with the changeset."""
256 """String. The active bookmark, if it is associated with the changeset."""
253 repo = context.resource(mapping, 'repo')
257 repo = context.resource(mapping, 'repo')
254 ctx = context.resource(mapping, 'ctx')
258 ctx = context.resource(mapping, 'ctx')
255 active = repo._activebookmark
259 active = repo._activebookmark
256 if active and active in ctx.bookmarks():
260 if active and active in ctx.bookmarks():
257 return active
261 return active
258 return ''
262 return ''
259
263
260 @templatekeyword('date', requires={'ctx'})
264 @templatekeyword('date', requires={'ctx'})
261 def showdate(context, mapping):
265 def showdate(context, mapping):
262 """Date information. The date when the changeset was committed."""
266 """Date information. The date when the changeset was committed."""
263 ctx = context.resource(mapping, 'ctx')
267 ctx = context.resource(mapping, 'ctx')
264 return ctx.date()
268 return ctx.date()
265
269
266 @templatekeyword('desc', requires={'ctx'})
270 @templatekeyword('desc', requires={'ctx'})
267 def showdescription(context, mapping):
271 def showdescription(context, mapping):
268 """String. The text of the changeset description."""
272 """String. The text of the changeset description."""
269 ctx = context.resource(mapping, 'ctx')
273 ctx = context.resource(mapping, 'ctx')
270 s = ctx.description()
274 s = ctx.description()
271 if isinstance(s, encoding.localstr):
275 if isinstance(s, encoding.localstr):
272 # try hard to preserve utf-8 bytes
276 # try hard to preserve utf-8 bytes
273 return encoding.tolocal(encoding.fromlocal(s).strip())
277 return encoding.tolocal(encoding.fromlocal(s).strip())
274 else:
278 else:
275 return s.strip()
279 return s.strip()
276
280
277 @templatekeyword('diffstat', requires={'ctx'})
281 @templatekeyword('diffstat', requires={'ctx'})
278 def showdiffstat(context, mapping):
282 def showdiffstat(context, mapping):
279 """String. Statistics of changes with the following format:
283 """String. Statistics of changes with the following format:
280 "modified files: +added/-removed lines"
284 "modified files: +added/-removed lines"
281 """
285 """
282 ctx = context.resource(mapping, 'ctx')
286 ctx = context.resource(mapping, 'ctx')
283 stats = patch.diffstatdata(util.iterlines(ctx.diff(noprefix=False)))
287 stats = patch.diffstatdata(util.iterlines(ctx.diff(noprefix=False)))
284 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
288 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
285 return '%d: +%d/-%d' % (len(stats), adds, removes)
289 return '%d: +%d/-%d' % (len(stats), adds, removes)
286
290
287 @templatekeyword('envvars', requires={'ui'})
291 @templatekeyword('envvars', requires={'ui'})
288 def showenvvars(context, mapping):
292 def showenvvars(context, mapping):
289 """A dictionary of environment variables. (EXPERIMENTAL)"""
293 """A dictionary of environment variables. (EXPERIMENTAL)"""
290 ui = context.resource(mapping, 'ui')
294 ui = context.resource(mapping, 'ui')
291 env = ui.exportableenviron()
295 env = ui.exportableenviron()
292 env = util.sortdict((k, env[k]) for k in sorted(env))
296 env = util.sortdict((k, env[k]) for k in sorted(env))
293 return compatdict(context, mapping, 'envvar', env, plural='envvars')
297 return compatdict(context, mapping, 'envvar', env, plural='envvars')
294
298
295 @templatekeyword('extras', requires={'ctx'})
299 @templatekeyword('extras', requires={'ctx'})
296 def showextras(context, mapping):
300 def showextras(context, mapping):
297 """List of dicts with key, value entries of the 'extras'
301 """List of dicts with key, value entries of the 'extras'
298 field of this changeset."""
302 field of this changeset."""
299 ctx = context.resource(mapping, 'ctx')
303 ctx = context.resource(mapping, 'ctx')
300 extras = ctx.extra()
304 extras = ctx.extra()
301 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
305 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
302 makemap = lambda k: {'key': k, 'value': extras[k]}
306 makemap = lambda k: {'key': k, 'value': extras[k]}
303 c = [makemap(k) for k in extras]
307 c = [makemap(k) for k in extras]
304 f = _showcompatlist(context, mapping, 'extra', c, plural='extras')
308 f = _showcompatlist(context, mapping, 'extra', c, plural='extras')
305 return _hybrid(f, extras, makemap,
309 return _hybrid(f, extras, makemap,
306 lambda k: '%s=%s' % (k, util.escapestr(extras[k])))
310 lambda k: '%s=%s' % (k, util.escapestr(extras[k])))
307
311
308 def _showfilesbystat(context, mapping, name, index):
312 def _showfilesbystat(context, mapping, name, index):
309 repo = context.resource(mapping, 'repo')
313 repo = context.resource(mapping, 'repo')
310 ctx = context.resource(mapping, 'ctx')
314 ctx = context.resource(mapping, 'ctx')
311 revcache = context.resource(mapping, 'revcache')
315 revcache = context.resource(mapping, 'revcache')
312 if 'files' not in revcache:
316 if 'files' not in revcache:
313 revcache['files'] = repo.status(ctx.p1(), ctx)[:3]
317 revcache['files'] = repo.status(ctx.p1(), ctx)[:3]
314 files = revcache['files'][index]
318 files = revcache['files'][index]
315 return compatlist(context, mapping, name, files, element='file')
319 return compatlist(context, mapping, name, files, element='file')
316
320
317 @templatekeyword('file_adds', requires={'repo', 'ctx', 'revcache'})
321 @templatekeyword('file_adds', requires={'repo', 'ctx', 'revcache'})
318 def showfileadds(context, mapping):
322 def showfileadds(context, mapping):
319 """List of strings. Files added by this changeset."""
323 """List of strings. Files added by this changeset."""
320 return _showfilesbystat(context, mapping, 'file_add', 1)
324 return _showfilesbystat(context, mapping, 'file_add', 1)
321
325
322 @templatekeyword('file_copies',
326 @templatekeyword('file_copies',
323 requires={'repo', 'ctx', 'cache', 'revcache'})
327 requires={'repo', 'ctx', 'cache', 'revcache'})
324 def showfilecopies(context, mapping):
328 def showfilecopies(context, mapping):
325 """List of strings. Files copied in this changeset with
329 """List of strings. Files copied in this changeset with
326 their sources.
330 their sources.
327 """
331 """
328 repo = context.resource(mapping, 'repo')
332 repo = context.resource(mapping, 'repo')
329 ctx = context.resource(mapping, 'ctx')
333 ctx = context.resource(mapping, 'ctx')
330 cache = context.resource(mapping, 'cache')
334 cache = context.resource(mapping, 'cache')
331 copies = context.resource(mapping, 'revcache').get('copies')
335 copies = context.resource(mapping, 'revcache').get('copies')
332 if copies is None:
336 if copies is None:
333 if 'getrenamed' not in cache:
337 if 'getrenamed' not in cache:
334 cache['getrenamed'] = getrenamedfn(repo)
338 cache['getrenamed'] = getrenamedfn(repo)
335 copies = []
339 copies = []
336 getrenamed = cache['getrenamed']
340 getrenamed = cache['getrenamed']
337 for fn in ctx.files():
341 for fn in ctx.files():
338 rename = getrenamed(fn, ctx.rev())
342 rename = getrenamed(fn, ctx.rev())
339 if rename:
343 if rename:
340 copies.append((fn, rename[0]))
344 copies.append((fn, rename[0]))
341
345
342 copies = util.sortdict(copies)
346 copies = util.sortdict(copies)
343 return compatdict(context, mapping, 'file_copy', copies,
347 return compatdict(context, mapping, 'file_copy', copies,
344 key='name', value='source', fmt='%s (%s)',
348 key='name', value='source', fmt='%s (%s)',
345 plural='file_copies')
349 plural='file_copies')
346
350
347 # showfilecopiesswitch() displays file copies only if copy records are
351 # showfilecopiesswitch() displays file copies only if copy records are
348 # provided before calling the templater, usually with a --copies
352 # provided before calling the templater, usually with a --copies
349 # command line switch.
353 # command line switch.
350 @templatekeyword('file_copies_switch', requires={'revcache'})
354 @templatekeyword('file_copies_switch', requires={'revcache'})
351 def showfilecopiesswitch(context, mapping):
355 def showfilecopiesswitch(context, mapping):
352 """List of strings. Like "file_copies" but displayed
356 """List of strings. Like "file_copies" but displayed
353 only if the --copied switch is set.
357 only if the --copied switch is set.
354 """
358 """
355 copies = context.resource(mapping, 'revcache').get('copies') or []
359 copies = context.resource(mapping, 'revcache').get('copies') or []
356 copies = util.sortdict(copies)
360 copies = util.sortdict(copies)
357 return compatdict(context, mapping, 'file_copy', copies,
361 return compatdict(context, mapping, 'file_copy', copies,
358 key='name', value='source', fmt='%s (%s)',
362 key='name', value='source', fmt='%s (%s)',
359 plural='file_copies')
363 plural='file_copies')
360
364
361 @templatekeyword('file_dels', requires={'repo', 'ctx', 'revcache'})
365 @templatekeyword('file_dels', requires={'repo', 'ctx', 'revcache'})
362 def showfiledels(context, mapping):
366 def showfiledels(context, mapping):
363 """List of strings. Files removed by this changeset."""
367 """List of strings. Files removed by this changeset."""
364 return _showfilesbystat(context, mapping, 'file_del', 2)
368 return _showfilesbystat(context, mapping, 'file_del', 2)
365
369
366 @templatekeyword('file_mods', requires={'repo', 'ctx', 'revcache'})
370 @templatekeyword('file_mods', requires={'repo', 'ctx', 'revcache'})
367 def showfilemods(context, mapping):
371 def showfilemods(context, mapping):
368 """List of strings. Files modified by this changeset."""
372 """List of strings. Files modified by this changeset."""
369 return _showfilesbystat(context, mapping, 'file_mod', 0)
373 return _showfilesbystat(context, mapping, 'file_mod', 0)
370
374
371 @templatekeyword('files', requires={'ctx'})
375 @templatekeyword('files', requires={'ctx'})
372 def showfiles(context, mapping):
376 def showfiles(context, mapping):
373 """List of strings. All files modified, added, or removed by this
377 """List of strings. All files modified, added, or removed by this
374 changeset.
378 changeset.
375 """
379 """
376 ctx = context.resource(mapping, 'ctx')
380 ctx = context.resource(mapping, 'ctx')
377 return compatlist(context, mapping, 'file', ctx.files())
381 return compatlist(context, mapping, 'file', ctx.files())
378
382
379 @templatekeyword('graphnode', requires={'repo', 'ctx'})
383 @templatekeyword('graphnode', requires={'repo', 'ctx'})
380 def showgraphnode(context, mapping):
384 def showgraphnode(context, mapping):
381 """String. The character representing the changeset node in an ASCII
385 """String. The character representing the changeset node in an ASCII
382 revision graph."""
386 revision graph."""
383 repo = context.resource(mapping, 'repo')
387 repo = context.resource(mapping, 'repo')
384 ctx = context.resource(mapping, 'ctx')
388 ctx = context.resource(mapping, 'ctx')
385 return getgraphnode(repo, ctx)
389 return getgraphnode(repo, ctx)
386
390
387 def getgraphnode(repo, ctx):
391 def getgraphnode(repo, ctx):
388 wpnodes = repo.dirstate.parents()
392 wpnodes = repo.dirstate.parents()
389 if wpnodes[1] == nullid:
393 if wpnodes[1] == nullid:
390 wpnodes = wpnodes[:1]
394 wpnodes = wpnodes[:1]
391 if ctx.node() in wpnodes:
395 if ctx.node() in wpnodes:
392 return '@'
396 return '@'
393 elif ctx.obsolete():
397 elif ctx.obsolete():
394 return 'x'
398 return 'x'
395 elif ctx.isunstable():
399 elif ctx.isunstable():
396 return '*'
400 return '*'
397 elif ctx.closesbranch():
401 elif ctx.closesbranch():
398 return '_'
402 return '_'
399 else:
403 else:
400 return 'o'
404 return 'o'
401
405
402 @templatekeyword('graphwidth', requires=())
406 @templatekeyword('graphwidth', requires=())
403 def showgraphwidth(context, mapping):
407 def showgraphwidth(context, mapping):
404 """Integer. The width of the graph drawn by 'log --graph' or zero."""
408 """Integer. The width of the graph drawn by 'log --graph' or zero."""
405 # just hosts documentation; should be overridden by template mapping
409 # just hosts documentation; should be overridden by template mapping
406 return 0
410 return 0
407
411
408 @templatekeyword('index', requires=())
412 @templatekeyword('index', requires=())
409 def showindex(context, mapping):
413 def showindex(context, mapping):
410 """Integer. The current iteration of the loop. (0 indexed)"""
414 """Integer. The current iteration of the loop. (0 indexed)"""
411 # just hosts documentation; should be overridden by template mapping
415 # just hosts documentation; should be overridden by template mapping
412 raise error.Abort(_("can't use index in this context"))
416 raise error.Abort(_("can't use index in this context"))
413
417
414 @templatekeyword('latesttag', requires={'repo', 'ctx', 'cache'})
418 @templatekeyword('latesttag', requires={'repo', 'ctx', 'cache'})
415 def showlatesttag(context, mapping):
419 def showlatesttag(context, mapping):
416 """List of strings. The global tags on the most recent globally
420 """List of strings. The global tags on the most recent globally
417 tagged ancestor of this changeset. If no such tags exist, the list
421 tagged ancestor of this changeset. If no such tags exist, the list
418 consists of the single string "null".
422 consists of the single string "null".
419 """
423 """
420 return showlatesttags(context, mapping, None)
424 return showlatesttags(context, mapping, None)
421
425
422 def showlatesttags(context, mapping, pattern):
426 def showlatesttags(context, mapping, pattern):
423 """helper method for the latesttag keyword and function"""
427 """helper method for the latesttag keyword and function"""
424 latesttags = getlatesttags(context, mapping, pattern)
428 latesttags = getlatesttags(context, mapping, pattern)
425
429
426 # latesttag[0] is an implementation detail for sorting csets on different
430 # latesttag[0] is an implementation detail for sorting csets on different
427 # branches in a stable manner- it is the date the tagged cset was created,
431 # branches in a stable manner- it is the date the tagged cset was created,
428 # not the date the tag was created. Therefore it isn't made visible here.
432 # not the date the tag was created. Therefore it isn't made visible here.
429 makemap = lambda v: {
433 makemap = lambda v: {
430 'changes': _showchangessincetag,
434 'changes': _showchangessincetag,
431 'distance': latesttags[1],
435 'distance': latesttags[1],
432 'latesttag': v, # BC with {latesttag % '{latesttag}'}
436 'latesttag': v, # BC with {latesttag % '{latesttag}'}
433 'tag': v
437 'tag': v
434 }
438 }
435
439
436 tags = latesttags[2]
440 tags = latesttags[2]
437 f = _showcompatlist(context, mapping, 'latesttag', tags, separator=':')
441 f = _showcompatlist(context, mapping, 'latesttag', tags, separator=':')
438 return _hybrid(f, tags, makemap, pycompat.identity)
442 return _hybrid(f, tags, makemap, pycompat.identity)
439
443
440 @templatekeyword('latesttagdistance', requires={'repo', 'ctx', 'cache'})
444 @templatekeyword('latesttagdistance', requires={'repo', 'ctx', 'cache'})
441 def showlatesttagdistance(context, mapping):
445 def showlatesttagdistance(context, mapping):
442 """Integer. Longest path to the latest tag."""
446 """Integer. Longest path to the latest tag."""
443 return getlatesttags(context, mapping)[1]
447 return getlatesttags(context, mapping)[1]
444
448
445 @templatekeyword('changessincelatesttag', requires={'repo', 'ctx', 'cache'})
449 @templatekeyword('changessincelatesttag', requires={'repo', 'ctx', 'cache'})
446 def showchangessincelatesttag(context, mapping):
450 def showchangessincelatesttag(context, mapping):
447 """Integer. All ancestors not in the latest tag."""
451 """Integer. All ancestors not in the latest tag."""
448 mapping = mapping.copy()
452 mapping = mapping.copy()
449 mapping['tag'] = getlatesttags(context, mapping)[2][0]
453 mapping['tag'] = getlatesttags(context, mapping)[2][0]
450 return _showchangessincetag(context, mapping)
454 return _showchangessincetag(context, mapping)
451
455
452 def _showchangessincetag(context, mapping):
456 def _showchangessincetag(context, mapping):
453 repo = context.resource(mapping, 'repo')
457 repo = context.resource(mapping, 'repo')
454 ctx = context.resource(mapping, 'ctx')
458 ctx = context.resource(mapping, 'ctx')
455 offset = 0
459 offset = 0
456 revs = [ctx.rev()]
460 revs = [ctx.rev()]
457 tag = context.symbol(mapping, 'tag')
461 tag = context.symbol(mapping, 'tag')
458
462
459 # The only() revset doesn't currently support wdir()
463 # The only() revset doesn't currently support wdir()
460 if ctx.rev() is None:
464 if ctx.rev() is None:
461 offset = 1
465 offset = 1
462 revs = [p.rev() for p in ctx.parents()]
466 revs = [p.rev() for p in ctx.parents()]
463
467
464 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
468 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
465
469
466 # teach templater latesttags.changes is switched to (context, mapping) API
470 # teach templater latesttags.changes is switched to (context, mapping) API
467 _showchangessincetag._requires = {'repo', 'ctx'}
471 _showchangessincetag._requires = {'repo', 'ctx'}
468
472
469 @templatekeyword('manifest', requires={'repo', 'ctx'})
473 @templatekeyword('manifest', requires={'repo', 'ctx'})
470 def showmanifest(context, mapping):
474 def showmanifest(context, mapping):
471 repo = context.resource(mapping, 'repo')
475 repo = context.resource(mapping, 'repo')
472 ctx = context.resource(mapping, 'ctx')
476 ctx = context.resource(mapping, 'ctx')
473 mnode = ctx.manifestnode()
477 mnode = ctx.manifestnode()
474 if mnode is None:
478 if mnode is None:
475 # just avoid crash, we might want to use the 'ff...' hash in future
479 # just avoid crash, we might want to use the 'ff...' hash in future
476 return
480 return
477 mrev = repo.manifestlog._revlog.rev(mnode)
481 mrev = repo.manifestlog._revlog.rev(mnode)
478 mhex = hex(mnode)
482 mhex = hex(mnode)
479 mapping = mapping.copy()
483 mapping = mapping.copy()
480 mapping.update({'rev': mrev, 'node': mhex})
484 mapping.update({'rev': mrev, 'node': mhex})
481 f = context.process('manifest', mapping)
485 f = context.process('manifest', mapping)
482 # TODO: perhaps 'ctx' should be dropped from mapping because manifest
486 # TODO: perhaps 'ctx' should be dropped from mapping because manifest
483 # rev and node are completely different from changeset's.
487 # rev and node are completely different from changeset's.
484 return _mappable(f, None, f, lambda x: {'rev': mrev, 'node': mhex})
488 return _mappable(f, None, f, lambda x: {'rev': mrev, 'node': mhex})
485
489
486 @templatekeyword('obsfate', requires={'ui', 'repo', 'ctx'})
490 @templatekeyword('obsfate', requires={'ui', 'repo', 'ctx'})
487 def showobsfate(context, mapping):
491 def showobsfate(context, mapping):
488 # this function returns a list containing pre-formatted obsfate strings.
492 # this function returns a list containing pre-formatted obsfate strings.
489 #
493 #
490 # This function will be replaced by templates fragments when we will have
494 # This function will be replaced by templates fragments when we will have
491 # the verbosity templatekw available.
495 # the verbosity templatekw available.
492 succsandmarkers = showsuccsandmarkers(context, mapping)
496 succsandmarkers = showsuccsandmarkers(context, mapping)
493
497
494 ui = context.resource(mapping, 'ui')
498 ui = context.resource(mapping, 'ui')
495 values = []
499 values = []
496
500
497 for x in succsandmarkers:
501 for x in succsandmarkers:
498 values.append(obsutil.obsfateprinter(x['successors'], x['markers'], ui))
502 values.append(obsutil.obsfateprinter(x['successors'], x['markers'], ui))
499
503
500 return compatlist(context, mapping, "fate", values)
504 return compatlist(context, mapping, "fate", values)
501
505
502 def shownames(context, mapping, namespace):
506 def shownames(context, mapping, namespace):
503 """helper method to generate a template keyword for a namespace"""
507 """helper method to generate a template keyword for a namespace"""
504 repo = context.resource(mapping, 'repo')
508 repo = context.resource(mapping, 'repo')
505 ctx = context.resource(mapping, 'ctx')
509 ctx = context.resource(mapping, 'ctx')
506 ns = repo.names[namespace]
510 ns = repo.names[namespace]
507 names = ns.names(repo, ctx.node())
511 names = ns.names(repo, ctx.node())
508 return compatlist(context, mapping, ns.templatename, names,
512 return compatlist(context, mapping, ns.templatename, names,
509 plural=namespace)
513 plural=namespace)
510
514
511 @templatekeyword('namespaces', requires={'repo', 'ctx'})
515 @templatekeyword('namespaces', requires={'repo', 'ctx'})
512 def shownamespaces(context, mapping):
516 def shownamespaces(context, mapping):
513 """Dict of lists. Names attached to this changeset per
517 """Dict of lists. Names attached to this changeset per
514 namespace."""
518 namespace."""
515 repo = context.resource(mapping, 'repo')
519 repo = context.resource(mapping, 'repo')
516 ctx = context.resource(mapping, 'ctx')
520 ctx = context.resource(mapping, 'ctx')
517
521
518 namespaces = util.sortdict()
522 namespaces = util.sortdict()
519 def makensmapfn(ns):
523 def makensmapfn(ns):
520 # 'name' for iterating over namespaces, templatename for local reference
524 # 'name' for iterating over namespaces, templatename for local reference
521 return lambda v: {'name': v, ns.templatename: v}
525 return lambda v: {'name': v, ns.templatename: v}
522
526
523 for k, ns in repo.names.iteritems():
527 for k, ns in repo.names.iteritems():
524 names = ns.names(repo, ctx.node())
528 names = ns.names(repo, ctx.node())
525 f = _showcompatlist(context, mapping, 'name', names)
529 f = _showcompatlist(context, mapping, 'name', names)
526 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
530 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity)
527
531
528 f = _showcompatlist(context, mapping, 'namespace', list(namespaces))
532 f = _showcompatlist(context, mapping, 'namespace', list(namespaces))
529
533
530 def makemap(ns):
534 def makemap(ns):
531 return {
535 return {
532 'namespace': ns,
536 'namespace': ns,
533 'names': namespaces[ns],
537 'names': namespaces[ns],
534 'builtin': repo.names[ns].builtin,
538 'builtin': repo.names[ns].builtin,
535 'colorname': repo.names[ns].colorname,
539 'colorname': repo.names[ns].colorname,
536 }
540 }
537
541
538 return _hybrid(f, namespaces, makemap, pycompat.identity)
542 return _hybrid(f, namespaces, makemap, pycompat.identity)
539
543
540 @templatekeyword('node', requires={'ctx'})
544 @templatekeyword('node', requires={'ctx'})
541 def shownode(context, mapping):
545 def shownode(context, mapping):
542 """String. The changeset identification hash, as a 40 hexadecimal
546 """String. The changeset identification hash, as a 40 hexadecimal
543 digit string.
547 digit string.
544 """
548 """
545 ctx = context.resource(mapping, 'ctx')
549 ctx = context.resource(mapping, 'ctx')
546 return ctx.hex()
550 return ctx.hex()
547
551
548 @templatekeyword('obsolete', requires={'ctx'})
552 @templatekeyword('obsolete', requires={'ctx'})
549 def showobsolete(context, mapping):
553 def showobsolete(context, mapping):
550 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
554 """String. Whether the changeset is obsolete. (EXPERIMENTAL)"""
551 ctx = context.resource(mapping, 'ctx')
555 ctx = context.resource(mapping, 'ctx')
552 if ctx.obsolete():
556 if ctx.obsolete():
553 return 'obsolete'
557 return 'obsolete'
554 return ''
558 return ''
555
559
556 @templatekeyword('peerurls', requires={'repo'})
560 @templatekeyword('peerurls', requires={'repo'})
557 def showpeerurls(context, mapping):
561 def showpeerurls(context, mapping):
558 """A dictionary of repository locations defined in the [paths] section
562 """A dictionary of repository locations defined in the [paths] section
559 of your configuration file."""
563 of your configuration file."""
560 repo = context.resource(mapping, 'repo')
564 repo = context.resource(mapping, 'repo')
561 # see commands.paths() for naming of dictionary keys
565 # see commands.paths() for naming of dictionary keys
562 paths = repo.ui.paths
566 paths = repo.ui.paths
563 urls = util.sortdict((k, p.rawloc) for k, p in sorted(paths.iteritems()))
567 urls = util.sortdict((k, p.rawloc) for k, p in sorted(paths.iteritems()))
564 def makemap(k):
568 def makemap(k):
565 p = paths[k]
569 p = paths[k]
566 d = {'name': k, 'url': p.rawloc}
570 d = {'name': k, 'url': p.rawloc}
567 d.update((o, v) for o, v in sorted(p.suboptions.iteritems()))
571 d.update((o, v) for o, v in sorted(p.suboptions.iteritems()))
568 return d
572 return d
569 return _hybrid(None, urls, makemap, lambda k: '%s=%s' % (k, urls[k]))
573 return _hybrid(None, urls, makemap, lambda k: '%s=%s' % (k, urls[k]))
570
574
571 @templatekeyword("predecessors", requires={'repo', 'ctx'})
575 @templatekeyword("predecessors", requires={'repo', 'ctx'})
572 def showpredecessors(context, mapping):
576 def showpredecessors(context, mapping):
573 """Returns the list if the closest visible successors. (EXPERIMENTAL)"""
577 """Returns the list if the closest visible successors. (EXPERIMENTAL)"""
574 repo = context.resource(mapping, 'repo')
578 repo = context.resource(mapping, 'repo')
575 ctx = context.resource(mapping, 'ctx')
579 ctx = context.resource(mapping, 'ctx')
576 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
580 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node()))
577 predecessors = map(hex, predecessors)
581 predecessors = map(hex, predecessors)
578
582
579 return _hybrid(None, predecessors,
583 return _hybrid(None, predecessors,
580 lambda x: {'ctx': repo[x], 'revcache': {}},
584 lambda x: {'ctx': repo[x], 'revcache': {}},
581 lambda x: scmutil.formatchangeid(repo[x]))
585 lambda x: scmutil.formatchangeid(repo[x]))
582
586
583 @templatekeyword('reporoot', requires={'repo'})
587 @templatekeyword('reporoot', requires={'repo'})
584 def showreporoot(context, mapping):
588 def showreporoot(context, mapping):
585 """String. The root directory of the current repository."""
589 """String. The root directory of the current repository."""
586 repo = context.resource(mapping, 'repo')
590 repo = context.resource(mapping, 'repo')
587 return repo.root
591 return repo.root
588
592
589 @templatekeyword("successorssets", requires={'repo', 'ctx'})
593 @templatekeyword("successorssets", requires={'repo', 'ctx'})
590 def showsuccessorssets(context, mapping):
594 def showsuccessorssets(context, mapping):
591 """Returns a string of sets of successors for a changectx. Format used
595 """Returns a string of sets of successors for a changectx. Format used
592 is: [ctx1, ctx2], [ctx3] if ctx has been splitted into ctx1 and ctx2
596 is: [ctx1, ctx2], [ctx3] if ctx has been splitted into ctx1 and ctx2
593 while also diverged into ctx3. (EXPERIMENTAL)"""
597 while also diverged into ctx3. (EXPERIMENTAL)"""
594 repo = context.resource(mapping, 'repo')
598 repo = context.resource(mapping, 'repo')
595 ctx = context.resource(mapping, 'ctx')
599 ctx = context.resource(mapping, 'ctx')
596 if not ctx.obsolete():
600 if not ctx.obsolete():
597 return ''
601 return ''
598
602
599 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
603 ssets = obsutil.successorssets(repo, ctx.node(), closest=True)
600 ssets = [[hex(n) for n in ss] for ss in ssets]
604 ssets = [[hex(n) for n in ss] for ss in ssets]
601
605
602 data = []
606 data = []
603 for ss in ssets:
607 for ss in ssets:
604 h = _hybrid(None, ss, lambda x: {'ctx': repo[x], 'revcache': {}},
608 h = _hybrid(None, ss, lambda x: {'ctx': repo[x], 'revcache': {}},
605 lambda x: scmutil.formatchangeid(repo[x]))
609 lambda x: scmutil.formatchangeid(repo[x]))
606 data.append(h)
610 data.append(h)
607
611
608 # Format the successorssets
612 # Format the successorssets
609 def render(d):
613 def render(d):
610 t = []
614 t = []
611 for i in d.gen():
615 for i in d.gen():
612 t.append(i)
616 t.append(i)
613 return "".join(t)
617 return "".join(t)
614
618
615 def gen(data):
619 def gen(data):
616 yield "; ".join(render(d) for d in data)
620 yield "; ".join(render(d) for d in data)
617
621
618 return _hybrid(gen(data), data, lambda x: {'successorset': x},
622 return _hybrid(gen(data), data, lambda x: {'successorset': x},
619 pycompat.identity)
623 pycompat.identity)
620
624
621 @templatekeyword("succsandmarkers", requires={'repo', 'ctx'})
625 @templatekeyword("succsandmarkers", requires={'repo', 'ctx'})
622 def showsuccsandmarkers(context, mapping):
626 def showsuccsandmarkers(context, mapping):
623 """Returns a list of dict for each final successor of ctx. The dict
627 """Returns a list of dict for each final successor of ctx. The dict
624 contains successors node id in "successors" keys and the list of
628 contains successors node id in "successors" keys and the list of
625 obs-markers from ctx to the set of successors in "markers".
629 obs-markers from ctx to the set of successors in "markers".
626 (EXPERIMENTAL)
630 (EXPERIMENTAL)
627 """
631 """
628 repo = context.resource(mapping, 'repo')
632 repo = context.resource(mapping, 'repo')
629 ctx = context.resource(mapping, 'ctx')
633 ctx = context.resource(mapping, 'ctx')
630
634
631 values = obsutil.successorsandmarkers(repo, ctx)
635 values = obsutil.successorsandmarkers(repo, ctx)
632
636
633 if values is None:
637 if values is None:
634 values = []
638 values = []
635
639
636 # Format successors and markers to avoid exposing binary to templates
640 # Format successors and markers to avoid exposing binary to templates
637 data = []
641 data = []
638 for i in values:
642 for i in values:
639 # Format successors
643 # Format successors
640 successors = i['successors']
644 successors = i['successors']
641
645
642 successors = [hex(n) for n in successors]
646 successors = [hex(n) for n in successors]
643 successors = _hybrid(None, successors,
647 successors = _hybrid(None, successors,
644 lambda x: {'ctx': repo[x], 'revcache': {}},
648 lambda x: {'ctx': repo[x], 'revcache': {}},
645 lambda x: scmutil.formatchangeid(repo[x]))
649 lambda x: scmutil.formatchangeid(repo[x]))
646
650
647 # Format markers
651 # Format markers
648 finalmarkers = []
652 finalmarkers = []
649 for m in i['markers']:
653 for m in i['markers']:
650 hexprec = hex(m[0])
654 hexprec = hex(m[0])
651 hexsucs = tuple(hex(n) for n in m[1])
655 hexsucs = tuple(hex(n) for n in m[1])
652 hexparents = None
656 hexparents = None
653 if m[5] is not None:
657 if m[5] is not None:
654 hexparents = tuple(hex(n) for n in m[5])
658 hexparents = tuple(hex(n) for n in m[5])
655 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
659 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:]
656 finalmarkers.append(newmarker)
660 finalmarkers.append(newmarker)
657
661
658 data.append({'successors': successors, 'markers': finalmarkers})
662 data.append({'successors': successors, 'markers': finalmarkers})
659
663
660 f = _showcompatlist(context, mapping, 'succsandmarkers', data)
664 f = _showcompatlist(context, mapping, 'succsandmarkers', data)
661 return _hybrid(f, data, lambda x: x, pycompat.identity)
665 return _hybrid(f, data, lambda x: x, pycompat.identity)
662
666
663 @templatekeyword('p1rev', requires={'ctx'})
667 @templatekeyword('p1rev', requires={'ctx'})
664 def showp1rev(context, mapping):
668 def showp1rev(context, mapping):
665 """Integer. The repository-local revision number of the changeset's
669 """Integer. The repository-local revision number of the changeset's
666 first parent, or -1 if the changeset has no parents."""
670 first parent, or -1 if the changeset has no parents."""
667 ctx = context.resource(mapping, 'ctx')
671 ctx = context.resource(mapping, 'ctx')
668 return ctx.p1().rev()
672 return ctx.p1().rev()
669
673
670 @templatekeyword('p2rev', requires={'ctx'})
674 @templatekeyword('p2rev', requires={'ctx'})
671 def showp2rev(context, mapping):
675 def showp2rev(context, mapping):
672 """Integer. The repository-local revision number of the changeset's
676 """Integer. The repository-local revision number of the changeset's
673 second parent, or -1 if the changeset has no second parent."""
677 second parent, or -1 if the changeset has no second parent."""
674 ctx = context.resource(mapping, 'ctx')
678 ctx = context.resource(mapping, 'ctx')
675 return ctx.p2().rev()
679 return ctx.p2().rev()
676
680
677 @templatekeyword('p1node', requires={'ctx'})
681 @templatekeyword('p1node', requires={'ctx'})
678 def showp1node(context, mapping):
682 def showp1node(context, mapping):
679 """String. The identification hash of the changeset's first parent,
683 """String. The identification hash of the changeset's first parent,
680 as a 40 digit hexadecimal string. If the changeset has no parents, all
684 as a 40 digit hexadecimal string. If the changeset has no parents, all
681 digits are 0."""
685 digits are 0."""
682 ctx = context.resource(mapping, 'ctx')
686 ctx = context.resource(mapping, 'ctx')
683 return ctx.p1().hex()
687 return ctx.p1().hex()
684
688
685 @templatekeyword('p2node', requires={'ctx'})
689 @templatekeyword('p2node', requires={'ctx'})
686 def showp2node(context, mapping):
690 def showp2node(context, mapping):
687 """String. The identification hash of the changeset's second
691 """String. The identification hash of the changeset's second
688 parent, as a 40 digit hexadecimal string. If the changeset has no second
692 parent, as a 40 digit hexadecimal string. If the changeset has no second
689 parent, all digits are 0."""
693 parent, all digits are 0."""
690 ctx = context.resource(mapping, 'ctx')
694 ctx = context.resource(mapping, 'ctx')
691 return ctx.p2().hex()
695 return ctx.p2().hex()
692
696
693 @templatekeyword('parents', requires={'repo', 'ctx'})
697 @templatekeyword('parents', requires={'repo', 'ctx'})
694 def showparents(context, mapping):
698 def showparents(context, mapping):
695 """List of strings. The parents of the changeset in "rev:node"
699 """List of strings. The parents of the changeset in "rev:node"
696 format. If the changeset has only one "natural" parent (the predecessor
700 format. If the changeset has only one "natural" parent (the predecessor
697 revision) nothing is shown."""
701 revision) nothing is shown."""
698 repo = context.resource(mapping, 'repo')
702 repo = context.resource(mapping, 'repo')
699 ctx = context.resource(mapping, 'ctx')
703 ctx = context.resource(mapping, 'ctx')
700 pctxs = scmutil.meaningfulparents(repo, ctx)
704 pctxs = scmutil.meaningfulparents(repo, ctx)
701 prevs = [p.rev() for p in pctxs]
705 prevs = [p.rev() for p in pctxs]
702 parents = [[('rev', p.rev()),
706 parents = [[('rev', p.rev()),
703 ('node', p.hex()),
707 ('node', p.hex()),
704 ('phase', p.phasestr())]
708 ('phase', p.phasestr())]
705 for p in pctxs]
709 for p in pctxs]
706 f = _showcompatlist(context, mapping, 'parent', parents)
710 f = _showcompatlist(context, mapping, 'parent', parents)
707 return _hybrid(f, prevs, lambda x: {'ctx': repo[x], 'revcache': {}},
711 return _hybrid(f, prevs, lambda x: {'ctx': repo[x], 'revcache': {}},
708 lambda x: scmutil.formatchangeid(repo[x]), keytype=int)
712 lambda x: scmutil.formatchangeid(repo[x]), keytype=int)
709
713
710 @templatekeyword('phase', requires={'ctx'})
714 @templatekeyword('phase', requires={'ctx'})
711 def showphase(context, mapping):
715 def showphase(context, mapping):
712 """String. The changeset phase name."""
716 """String. The changeset phase name."""
713 ctx = context.resource(mapping, 'ctx')
717 ctx = context.resource(mapping, 'ctx')
714 return ctx.phasestr()
718 return ctx.phasestr()
715
719
716 @templatekeyword('phaseidx', requires={'ctx'})
720 @templatekeyword('phaseidx', requires={'ctx'})
717 def showphaseidx(context, mapping):
721 def showphaseidx(context, mapping):
718 """Integer. The changeset phase index. (ADVANCED)"""
722 """Integer. The changeset phase index. (ADVANCED)"""
719 ctx = context.resource(mapping, 'ctx')
723 ctx = context.resource(mapping, 'ctx')
720 return ctx.phase()
724 return ctx.phase()
721
725
722 @templatekeyword('rev', requires={'ctx'})
726 @templatekeyword('rev', requires={'ctx'})
723 def showrev(context, mapping):
727 def showrev(context, mapping):
724 """Integer. The repository-local changeset revision number."""
728 """Integer. The repository-local changeset revision number."""
725 ctx = context.resource(mapping, 'ctx')
729 ctx = context.resource(mapping, 'ctx')
726 return scmutil.intrev(ctx)
730 return scmutil.intrev(ctx)
727
731
728 def showrevslist(context, mapping, name, revs):
732 def showrevslist(context, mapping, name, revs):
729 """helper to generate a list of revisions in which a mapped template will
733 """helper to generate a list of revisions in which a mapped template will
730 be evaluated"""
734 be evaluated"""
731 repo = context.resource(mapping, 'repo')
735 repo = context.resource(mapping, 'repo')
732 f = _showcompatlist(context, mapping, name, ['%d' % r for r in revs])
736 f = _showcompatlist(context, mapping, name, ['%d' % r for r in revs])
733 return _hybrid(f, revs,
737 return _hybrid(f, revs,
734 lambda x: {name: x, 'ctx': repo[x], 'revcache': {}},
738 lambda x: {name: x, 'ctx': repo[x], 'revcache': {}},
735 pycompat.identity, keytype=int)
739 pycompat.identity, keytype=int)
736
740
737 @templatekeyword('subrepos', requires={'ctx'})
741 @templatekeyword('subrepos', requires={'ctx'})
738 def showsubrepos(context, mapping):
742 def showsubrepos(context, mapping):
739 """List of strings. Updated subrepositories in the changeset."""
743 """List of strings. Updated subrepositories in the changeset."""
740 ctx = context.resource(mapping, 'ctx')
744 ctx = context.resource(mapping, 'ctx')
741 substate = ctx.substate
745 substate = ctx.substate
742 if not substate:
746 if not substate:
743 return compatlist(context, mapping, 'subrepo', [])
747 return compatlist(context, mapping, 'subrepo', [])
744 psubstate = ctx.parents()[0].substate or {}
748 psubstate = ctx.parents()[0].substate or {}
745 subrepos = []
749 subrepos = []
746 for sub in substate:
750 for sub in substate:
747 if sub not in psubstate or substate[sub] != psubstate[sub]:
751 if sub not in psubstate or substate[sub] != psubstate[sub]:
748 subrepos.append(sub) # modified or newly added in ctx
752 subrepos.append(sub) # modified or newly added in ctx
749 for sub in psubstate:
753 for sub in psubstate:
750 if sub not in substate:
754 if sub not in substate:
751 subrepos.append(sub) # removed in ctx
755 subrepos.append(sub) # removed in ctx
752 return compatlist(context, mapping, 'subrepo', sorted(subrepos))
756 return compatlist(context, mapping, 'subrepo', sorted(subrepos))
753
757
754 # don't remove "showtags" definition, even though namespaces will put
758 # don't remove "showtags" definition, even though namespaces will put
755 # a helper function for "tags" keyword into "keywords" map automatically,
759 # a helper function for "tags" keyword into "keywords" map automatically,
756 # because online help text is built without namespaces initialization
760 # because online help text is built without namespaces initialization
757 @templatekeyword('tags', requires={'repo', 'ctx'})
761 @templatekeyword('tags', requires={'repo', 'ctx'})
758 def showtags(context, mapping):
762 def showtags(context, mapping):
759 """List of strings. Any tags associated with the changeset."""
763 """List of strings. Any tags associated with the changeset."""
760 return shownames(context, mapping, 'tags')
764 return shownames(context, mapping, 'tags')
761
765
762 @templatekeyword('termwidth', requires={'ui'})
766 @templatekeyword('termwidth', requires={'ui'})
763 def showtermwidth(context, mapping):
767 def showtermwidth(context, mapping):
764 """Integer. The width of the current terminal."""
768 """Integer. The width of the current terminal."""
765 ui = context.resource(mapping, 'ui')
769 ui = context.resource(mapping, 'ui')
766 return ui.termwidth()
770 return ui.termwidth()
767
771
768 @templatekeyword('instabilities', requires={'ctx'})
772 @templatekeyword('instabilities', requires={'ctx'})
769 def showinstabilities(context, mapping):
773 def showinstabilities(context, mapping):
770 """List of strings. Evolution instabilities affecting the changeset.
774 """List of strings. Evolution instabilities affecting the changeset.
771 (EXPERIMENTAL)
775 (EXPERIMENTAL)
772 """
776 """
773 ctx = context.resource(mapping, 'ctx')
777 ctx = context.resource(mapping, 'ctx')
774 return compatlist(context, mapping, 'instability', ctx.instabilities(),
778 return compatlist(context, mapping, 'instability', ctx.instabilities(),
775 plural='instabilities')
779 plural='instabilities')
776
780
777 @templatekeyword('verbosity', requires={'ui'})
781 @templatekeyword('verbosity', requires={'ui'})
778 def showverbosity(context, mapping):
782 def showverbosity(context, mapping):
779 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
783 """String. The current output verbosity in 'debug', 'quiet', 'verbose',
780 or ''."""
784 or ''."""
781 ui = context.resource(mapping, 'ui')
785 ui = context.resource(mapping, 'ui')
782 # see logcmdutil.changesettemplater for priority of these flags
786 # see logcmdutil.changesettemplater for priority of these flags
783 if ui.debugflag:
787 if ui.debugflag:
784 return 'debug'
788 return 'debug'
785 elif ui.quiet:
789 elif ui.quiet:
786 return 'quiet'
790 return 'quiet'
787 elif ui.verbose:
791 elif ui.verbose:
788 return 'verbose'
792 return 'verbose'
789 return ''
793 return ''
790
794
791 def loadkeyword(ui, extname, registrarobj):
795 def loadkeyword(ui, extname, registrarobj):
792 """Load template keyword from specified registrarobj
796 """Load template keyword from specified registrarobj
793 """
797 """
794 for name, func in registrarobj._table.iteritems():
798 for name, func in registrarobj._table.iteritems():
795 keywords[name] = func
799 keywords[name] = func
796
800
797 # tell hggettext to extract docstrings from these functions:
801 # tell hggettext to extract docstrings from these functions:
798 i18nfunctions = keywords.values()
802 i18nfunctions = keywords.values()
General Comments 0
You need to be logged in to leave comments. Login now