##// END OF EJS Templates
templatekw: keep raw list or dict in _hybrid object...
Yuya Nishihara -
r24239:31f9b1b1 default
parent child Browse files
Show More
@@ -1,453 +1,457
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 node import hex
8 from node import hex
9 import patch, util, error
9 import patch, util, error
10 import hbisect
10 import hbisect
11
11
12 # This helper class allows us to handle both:
12 # This helper class allows us to handle both:
13 # "{files}" (legacy command-line-specific list hack) and
13 # "{files}" (legacy command-line-specific list hack) and
14 # "{files % '{file}\n'}" (hgweb-style with inlining and function support)
14 # "{files % '{file}\n'}" (hgweb-style with inlining and function support)
15
15
16 class _hybrid(object):
16 class _hybrid(object):
17 def __init__(self, gen, values, joinfmt=None):
17 def __init__(self, gen, values, makemap, joinfmt=None):
18 self.gen = gen
18 self.gen = gen
19 self.values = values
19 self.values = values
20 self._makemap = makemap
20 if joinfmt:
21 if joinfmt:
21 self.joinfmt = joinfmt
22 self.joinfmt = joinfmt
22 else:
23 else:
23 self.joinfmt = lambda x: x.values()[0]
24 self.joinfmt = lambda x: x.values()[0]
24 def __iter__(self):
25 def __iter__(self):
25 return self.gen
26 return self.gen
26 def __call__(self):
27 def __call__(self):
28 makemap = self._makemap
27 for x in self.values:
29 for x in self.values:
28 yield x
30 yield makemap(x)
29 def __len__(self):
31 def __len__(self):
30 return len(self.values)
32 return len(self.values)
31
33
32 def showlist(name, values, plural=None, element=None, **args):
34 def showlist(name, values, plural=None, element=None, **args):
33 if not element:
35 if not element:
34 element = name
36 element = name
35 f = _showlist(name, values, plural, **args)
37 f = _showlist(name, values, plural, **args)
36 return _hybrid(f, [{element: x} for x in values])
38 return _hybrid(f, values, lambda x: {element: x})
37
39
38 def _showlist(name, values, plural=None, **args):
40 def _showlist(name, values, plural=None, **args):
39 '''expand set of values.
41 '''expand set of values.
40 name is name of key in template map.
42 name is name of key in template map.
41 values is list of strings or dicts.
43 values is list of strings or dicts.
42 plural is plural of name, if not simply name + 's'.
44 plural is plural of name, if not simply name + 's'.
43
45
44 expansion works like this, given name 'foo'.
46 expansion works like this, given name 'foo'.
45
47
46 if values is empty, expand 'no_foos'.
48 if values is empty, expand 'no_foos'.
47
49
48 if 'foo' not in template map, return values as a string,
50 if 'foo' not in template map, return values as a string,
49 joined by space.
51 joined by space.
50
52
51 expand 'start_foos'.
53 expand 'start_foos'.
52
54
53 for each value, expand 'foo'. if 'last_foo' in template
55 for each value, expand 'foo'. if 'last_foo' in template
54 map, expand it instead of 'foo' for last key.
56 map, expand it instead of 'foo' for last key.
55
57
56 expand 'end_foos'.
58 expand 'end_foos'.
57 '''
59 '''
58 templ = args['templ']
60 templ = args['templ']
59 if plural:
61 if plural:
60 names = plural
62 names = plural
61 else: names = name + 's'
63 else: names = name + 's'
62 if not values:
64 if not values:
63 noname = 'no_' + names
65 noname = 'no_' + names
64 if noname in templ:
66 if noname in templ:
65 yield templ(noname, **args)
67 yield templ(noname, **args)
66 return
68 return
67 if name not in templ:
69 if name not in templ:
68 if isinstance(values[0], str):
70 if isinstance(values[0], str):
69 yield ' '.join(values)
71 yield ' '.join(values)
70 else:
72 else:
71 for v in values:
73 for v in values:
72 yield dict(v, **args)
74 yield dict(v, **args)
73 return
75 return
74 startname = 'start_' + names
76 startname = 'start_' + names
75 if startname in templ:
77 if startname in templ:
76 yield templ(startname, **args)
78 yield templ(startname, **args)
77 vargs = args.copy()
79 vargs = args.copy()
78 def one(v, tag=name):
80 def one(v, tag=name):
79 try:
81 try:
80 vargs.update(v)
82 vargs.update(v)
81 except (AttributeError, ValueError):
83 except (AttributeError, ValueError):
82 try:
84 try:
83 for a, b in v:
85 for a, b in v:
84 vargs[a] = b
86 vargs[a] = b
85 except ValueError:
87 except ValueError:
86 vargs[name] = v
88 vargs[name] = v
87 return templ(tag, **vargs)
89 return templ(tag, **vargs)
88 lastname = 'last_' + name
90 lastname = 'last_' + name
89 if lastname in templ:
91 if lastname in templ:
90 last = values.pop()
92 last = values.pop()
91 else:
93 else:
92 last = None
94 last = None
93 for v in values:
95 for v in values:
94 yield one(v)
96 yield one(v)
95 if last is not None:
97 if last is not None:
96 yield one(last, tag=lastname)
98 yield one(last, tag=lastname)
97 endname = 'end_' + names
99 endname = 'end_' + names
98 if endname in templ:
100 if endname in templ:
99 yield templ(endname, **args)
101 yield templ(endname, **args)
100
102
101 def getfiles(repo, ctx, revcache):
103 def getfiles(repo, ctx, revcache):
102 if 'files' not in revcache:
104 if 'files' not in revcache:
103 revcache['files'] = repo.status(ctx.p1().node(), ctx.node())[:3]
105 revcache['files'] = repo.status(ctx.p1().node(), ctx.node())[:3]
104 return revcache['files']
106 return revcache['files']
105
107
106 def getlatesttags(repo, ctx, cache):
108 def getlatesttags(repo, ctx, cache):
107 '''return date, distance and name for the latest tag of rev'''
109 '''return date, distance and name for the latest tag of rev'''
108
110
109 if 'latesttags' not in cache:
111 if 'latesttags' not in cache:
110 # Cache mapping from rev to a tuple with tag date, tag
112 # Cache mapping from rev to a tuple with tag date, tag
111 # distance and tag name
113 # distance and tag name
112 cache['latesttags'] = {-1: (0, 0, 'null')}
114 cache['latesttags'] = {-1: (0, 0, 'null')}
113 latesttags = cache['latesttags']
115 latesttags = cache['latesttags']
114
116
115 rev = ctx.rev()
117 rev = ctx.rev()
116 todo = [rev]
118 todo = [rev]
117 while todo:
119 while todo:
118 rev = todo.pop()
120 rev = todo.pop()
119 if rev in latesttags:
121 if rev in latesttags:
120 continue
122 continue
121 ctx = repo[rev]
123 ctx = repo[rev]
122 tags = [t for t in ctx.tags()
124 tags = [t for t in ctx.tags()
123 if (repo.tagtype(t) and repo.tagtype(t) != 'local')]
125 if (repo.tagtype(t) and repo.tagtype(t) != 'local')]
124 if tags:
126 if tags:
125 latesttags[rev] = ctx.date()[0], 0, ':'.join(sorted(tags))
127 latesttags[rev] = ctx.date()[0], 0, ':'.join(sorted(tags))
126 continue
128 continue
127 try:
129 try:
128 # The tuples are laid out so the right one can be found by
130 # The tuples are laid out so the right one can be found by
129 # comparison.
131 # comparison.
130 pdate, pdist, ptag = max(
132 pdate, pdist, ptag = max(
131 latesttags[p.rev()] for p in ctx.parents())
133 latesttags[p.rev()] for p in ctx.parents())
132 except KeyError:
134 except KeyError:
133 # Cache miss - recurse
135 # Cache miss - recurse
134 todo.append(rev)
136 todo.append(rev)
135 todo.extend(p.rev() for p in ctx.parents())
137 todo.extend(p.rev() for p in ctx.parents())
136 continue
138 continue
137 latesttags[rev] = pdate, pdist + 1, ptag
139 latesttags[rev] = pdate, pdist + 1, ptag
138 return latesttags[rev]
140 return latesttags[rev]
139
141
140 def getrenamedfn(repo, endrev=None):
142 def getrenamedfn(repo, endrev=None):
141 rcache = {}
143 rcache = {}
142 if endrev is None:
144 if endrev is None:
143 endrev = len(repo)
145 endrev = len(repo)
144
146
145 def getrenamed(fn, rev):
147 def getrenamed(fn, rev):
146 '''looks up all renames for a file (up to endrev) the first
148 '''looks up all renames for a file (up to endrev) the first
147 time the file is given. It indexes on the changerev and only
149 time the file is given. It indexes on the changerev and only
148 parses the manifest if linkrev != changerev.
150 parses the manifest if linkrev != changerev.
149 Returns rename info for fn at changerev rev.'''
151 Returns rename info for fn at changerev rev.'''
150 if fn not in rcache:
152 if fn not in rcache:
151 rcache[fn] = {}
153 rcache[fn] = {}
152 fl = repo.file(fn)
154 fl = repo.file(fn)
153 for i in fl:
155 for i in fl:
154 lr = fl.linkrev(i)
156 lr = fl.linkrev(i)
155 renamed = fl.renamed(fl.node(i))
157 renamed = fl.renamed(fl.node(i))
156 rcache[fn][lr] = renamed
158 rcache[fn][lr] = renamed
157 if lr >= endrev:
159 if lr >= endrev:
158 break
160 break
159 if rev in rcache[fn]:
161 if rev in rcache[fn]:
160 return rcache[fn][rev]
162 return rcache[fn][rev]
161
163
162 # If linkrev != rev (i.e. rev not found in rcache) fallback to
164 # If linkrev != rev (i.e. rev not found in rcache) fallback to
163 # filectx logic.
165 # filectx logic.
164 try:
166 try:
165 return repo[rev][fn].renamed()
167 return repo[rev][fn].renamed()
166 except error.LookupError:
168 except error.LookupError:
167 return None
169 return None
168
170
169 return getrenamed
171 return getrenamed
170
172
171
173
172 def showauthor(repo, ctx, templ, **args):
174 def showauthor(repo, ctx, templ, **args):
173 """:author: String. The unmodified author of the changeset."""
175 """:author: String. The unmodified author of the changeset."""
174 return ctx.user()
176 return ctx.user()
175
177
176 def showbisect(repo, ctx, templ, **args):
178 def showbisect(repo, ctx, templ, **args):
177 """:bisect: String. The changeset bisection status."""
179 """:bisect: String. The changeset bisection status."""
178 return hbisect.label(repo, ctx.node())
180 return hbisect.label(repo, ctx.node())
179
181
180 def showbranch(**args):
182 def showbranch(**args):
181 """:branch: String. The name of the branch on which the changeset was
183 """:branch: String. The name of the branch on which the changeset was
182 committed.
184 committed.
183 """
185 """
184 return args['ctx'].branch()
186 return args['ctx'].branch()
185
187
186 def showbranches(**args):
188 def showbranches(**args):
187 """:branches: List of strings. The name of the branch on which the
189 """:branches: List of strings. The name of the branch on which the
188 changeset was committed. Will be empty if the branch name was
190 changeset was committed. Will be empty if the branch name was
189 default.
191 default.
190 """
192 """
191 branch = args['ctx'].branch()
193 branch = args['ctx'].branch()
192 if branch != 'default':
194 if branch != 'default':
193 return showlist('branch', [branch], plural='branches', **args)
195 return showlist('branch', [branch], plural='branches', **args)
194 return showlist('branch', [], plural='branches', **args)
196 return showlist('branch', [], plural='branches', **args)
195
197
196 def showbookmarks(**args):
198 def showbookmarks(**args):
197 """:bookmarks: List of strings. Any bookmarks associated with the
199 """:bookmarks: List of strings. Any bookmarks associated with the
198 changeset.
200 changeset.
199 """
201 """
200 repo = args['ctx']._repo
202 repo = args['ctx']._repo
201 bookmarks = args['ctx'].bookmarks()
203 bookmarks = args['ctx'].bookmarks()
202 current = repo._bookmarkcurrent
204 current = repo._bookmarkcurrent
203 makemap = lambda v: {'bookmark': v, 'current': current}
205 makemap = lambda v: {'bookmark': v, 'current': current}
204 c = [makemap(v) for v in bookmarks]
205 f = _showlist('bookmark', bookmarks, **args)
206 f = _showlist('bookmark', bookmarks, **args)
206 return _hybrid(f, c, lambda x: x['bookmark'])
207 return _hybrid(f, bookmarks, makemap, lambda x: x['bookmark'])
207
208
208 def showchildren(**args):
209 def showchildren(**args):
209 """:children: List of strings. The children of the changeset."""
210 """:children: List of strings. The children of the changeset."""
210 ctx = args['ctx']
211 ctx = args['ctx']
211 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
212 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
212 return showlist('children', childrevs, element='child', **args)
213 return showlist('children', childrevs, element='child', **args)
213
214
214 def showcurrentbookmark(**args):
215 def showcurrentbookmark(**args):
215 """:currentbookmark: String. The active bookmark, if it is
216 """:currentbookmark: String. The active bookmark, if it is
216 associated with the changeset"""
217 associated with the changeset"""
217 import bookmarks as bookmarks # to avoid circular import issues
218 import bookmarks as bookmarks # to avoid circular import issues
218 repo = args['repo']
219 repo = args['repo']
219 if bookmarks.iscurrent(repo):
220 if bookmarks.iscurrent(repo):
220 current = repo._bookmarkcurrent
221 current = repo._bookmarkcurrent
221 if current in args['ctx'].bookmarks():
222 if current in args['ctx'].bookmarks():
222 return current
223 return current
223 return ''
224 return ''
224
225
225 def showdate(repo, ctx, templ, **args):
226 def showdate(repo, ctx, templ, **args):
226 """:date: Date information. The date when the changeset was committed."""
227 """:date: Date information. The date when the changeset was committed."""
227 return ctx.date()
228 return ctx.date()
228
229
229 def showdescription(repo, ctx, templ, **args):
230 def showdescription(repo, ctx, templ, **args):
230 """:desc: String. The text of the changeset description."""
231 """:desc: String. The text of the changeset description."""
231 return ctx.description().strip()
232 return ctx.description().strip()
232
233
233 def showdiffstat(repo, ctx, templ, **args):
234 def showdiffstat(repo, ctx, templ, **args):
234 """:diffstat: String. Statistics of changes with the following format:
235 """:diffstat: String. Statistics of changes with the following format:
235 "modified files: +added/-removed lines"
236 "modified files: +added/-removed lines"
236 """
237 """
237 stats = patch.diffstatdata(util.iterlines(ctx.diff()))
238 stats = patch.diffstatdata(util.iterlines(ctx.diff()))
238 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
239 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
239 return '%s: +%s/-%s' % (len(stats), adds, removes)
240 return '%s: +%s/-%s' % (len(stats), adds, removes)
240
241
241 def showextras(**args):
242 def showextras(**args):
242 """:extras: List of dicts with key, value entries of the 'extras'
243 """:extras: List of dicts with key, value entries of the 'extras'
243 field of this changeset."""
244 field of this changeset."""
244 extras = args['ctx'].extra()
245 extras = args['ctx'].extra()
245 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
246 extras = util.sortdict((k, extras[k]) for k in sorted(extras))
246 makemap = lambda k: {'key': k, 'value': extras[k]}
247 makemap = lambda k: {'key': k, 'value': extras[k]}
247 c = [makemap(k) for k in extras]
248 c = [makemap(k) for k in extras]
248 f = _showlist('extra', c, plural='extras', **args)
249 f = _showlist('extra', c, plural='extras', **args)
249 return _hybrid(f, c, lambda x: '%s=%s' % (x['key'], x['value']))
250 return _hybrid(f, extras, makemap,
251 lambda x: '%s=%s' % (x['key'], x['value']))
250
252
251 def showfileadds(**args):
253 def showfileadds(**args):
252 """:file_adds: List of strings. Files added by this changeset."""
254 """:file_adds: List of strings. Files added by this changeset."""
253 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
255 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
254 return showlist('file_add', getfiles(repo, ctx, revcache)[1],
256 return showlist('file_add', getfiles(repo, ctx, revcache)[1],
255 element='file', **args)
257 element='file', **args)
256
258
257 def showfilecopies(**args):
259 def showfilecopies(**args):
258 """:file_copies: List of strings. Files copied in this changeset with
260 """:file_copies: List of strings. Files copied in this changeset with
259 their sources.
261 their sources.
260 """
262 """
261 cache, ctx = args['cache'], args['ctx']
263 cache, ctx = args['cache'], args['ctx']
262 copies = args['revcache'].get('copies')
264 copies = args['revcache'].get('copies')
263 if copies is None:
265 if copies is None:
264 if 'getrenamed' not in cache:
266 if 'getrenamed' not in cache:
265 cache['getrenamed'] = getrenamedfn(args['repo'])
267 cache['getrenamed'] = getrenamedfn(args['repo'])
266 copies = []
268 copies = []
267 getrenamed = cache['getrenamed']
269 getrenamed = cache['getrenamed']
268 for fn in ctx.files():
270 for fn in ctx.files():
269 rename = getrenamed(fn, ctx.rev())
271 rename = getrenamed(fn, ctx.rev())
270 if rename:
272 if rename:
271 copies.append((fn, rename[0]))
273 copies.append((fn, rename[0]))
272
274
273 copies = util.sortdict(copies)
275 copies = util.sortdict(copies)
274 makemap = lambda k: {'name': k, 'source': copies[k]}
276 makemap = lambda k: {'name': k, 'source': copies[k]}
275 c = [makemap(k) for k in copies]
277 c = [makemap(k) for k in copies]
276 f = _showlist('file_copy', c, plural='file_copies', **args)
278 f = _showlist('file_copy', c, plural='file_copies', **args)
277 return _hybrid(f, c, lambda x: '%s (%s)' % (x['name'], x['source']))
279 return _hybrid(f, copies, makemap,
280 lambda x: '%s (%s)' % (x['name'], x['source']))
278
281
279 # showfilecopiesswitch() displays file copies only if copy records are
282 # showfilecopiesswitch() displays file copies only if copy records are
280 # provided before calling the templater, usually with a --copies
283 # provided before calling the templater, usually with a --copies
281 # command line switch.
284 # command line switch.
282 def showfilecopiesswitch(**args):
285 def showfilecopiesswitch(**args):
283 """:file_copies_switch: List of strings. Like "file_copies" but displayed
286 """:file_copies_switch: List of strings. Like "file_copies" but displayed
284 only if the --copied switch is set.
287 only if the --copied switch is set.
285 """
288 """
286 copies = args['revcache'].get('copies') or []
289 copies = args['revcache'].get('copies') or []
287 copies = util.sortdict(copies)
290 copies = util.sortdict(copies)
288 makemap = lambda k: {'name': k, 'source': copies[k]}
291 makemap = lambda k: {'name': k, 'source': copies[k]}
289 c = [makemap(k) for k in copies]
292 c = [makemap(k) for k in copies]
290 f = _showlist('file_copy', c, plural='file_copies', **args)
293 f = _showlist('file_copy', c, plural='file_copies', **args)
291 return _hybrid(f, c, lambda x: '%s (%s)' % (x['name'], x['source']))
294 return _hybrid(f, copies, makemap,
295 lambda x: '%s (%s)' % (x['name'], x['source']))
292
296
293 def showfiledels(**args):
297 def showfiledels(**args):
294 """:file_dels: List of strings. Files removed by this changeset."""
298 """:file_dels: List of strings. Files removed by this changeset."""
295 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
299 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
296 return showlist('file_del', getfiles(repo, ctx, revcache)[2],
300 return showlist('file_del', getfiles(repo, ctx, revcache)[2],
297 element='file', **args)
301 element='file', **args)
298
302
299 def showfilemods(**args):
303 def showfilemods(**args):
300 """:file_mods: List of strings. Files modified by this changeset."""
304 """:file_mods: List of strings. Files modified by this changeset."""
301 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
305 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
302 return showlist('file_mod', getfiles(repo, ctx, revcache)[0],
306 return showlist('file_mod', getfiles(repo, ctx, revcache)[0],
303 element='file', **args)
307 element='file', **args)
304
308
305 def showfiles(**args):
309 def showfiles(**args):
306 """:files: List of strings. All files modified, added, or removed by this
310 """:files: List of strings. All files modified, added, or removed by this
307 changeset.
311 changeset.
308 """
312 """
309 return showlist('file', args['ctx'].files(), **args)
313 return showlist('file', args['ctx'].files(), **args)
310
314
311 def showlatesttag(repo, ctx, templ, cache, **args):
315 def showlatesttag(repo, ctx, templ, cache, **args):
312 """:latesttag: String. Most recent global tag in the ancestors of this
316 """:latesttag: String. Most recent global tag in the ancestors of this
313 changeset.
317 changeset.
314 """
318 """
315 return getlatesttags(repo, ctx, cache)[2]
319 return getlatesttags(repo, ctx, cache)[2]
316
320
317 def showlatesttagdistance(repo, ctx, templ, cache, **args):
321 def showlatesttagdistance(repo, ctx, templ, cache, **args):
318 """:latesttagdistance: Integer. Longest path to the latest tag."""
322 """:latesttagdistance: Integer. Longest path to the latest tag."""
319 return getlatesttags(repo, ctx, cache)[1]
323 return getlatesttags(repo, ctx, cache)[1]
320
324
321 def showmanifest(**args):
325 def showmanifest(**args):
322 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
326 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
323 args = args.copy()
327 args = args.copy()
324 args.update({'rev': repo.manifest.rev(ctx.changeset()[0]),
328 args.update({'rev': repo.manifest.rev(ctx.changeset()[0]),
325 'node': hex(ctx.changeset()[0])})
329 'node': hex(ctx.changeset()[0])})
326 return templ('manifest', **args)
330 return templ('manifest', **args)
327
331
328 def shownode(repo, ctx, templ, **args):
332 def shownode(repo, ctx, templ, **args):
329 """:node: String. The changeset identification hash, as a 40 hexadecimal
333 """:node: String. The changeset identification hash, as a 40 hexadecimal
330 digit string.
334 digit string.
331 """
335 """
332 return ctx.hex()
336 return ctx.hex()
333
337
334 def showp1rev(repo, ctx, templ, **args):
338 def showp1rev(repo, ctx, templ, **args):
335 """:p1rev: Integer. The repository-local revision number of the changeset's
339 """:p1rev: Integer. The repository-local revision number of the changeset's
336 first parent, or -1 if the changeset has no parents."""
340 first parent, or -1 if the changeset has no parents."""
337 return ctx.p1().rev()
341 return ctx.p1().rev()
338
342
339 def showp2rev(repo, ctx, templ, **args):
343 def showp2rev(repo, ctx, templ, **args):
340 """:p2rev: Integer. The repository-local revision number of the changeset's
344 """:p2rev: Integer. The repository-local revision number of the changeset's
341 second parent, or -1 if the changeset has no second parent."""
345 second parent, or -1 if the changeset has no second parent."""
342 return ctx.p2().rev()
346 return ctx.p2().rev()
343
347
344 def showp1node(repo, ctx, templ, **args):
348 def showp1node(repo, ctx, templ, **args):
345 """:p1node: String. The identification hash of the changeset's first parent,
349 """:p1node: String. The identification hash of the changeset's first parent,
346 as a 40 digit hexadecimal string. If the changeset has no parents, all
350 as a 40 digit hexadecimal string. If the changeset has no parents, all
347 digits are 0."""
351 digits are 0."""
348 return ctx.p1().hex()
352 return ctx.p1().hex()
349
353
350 def showp2node(repo, ctx, templ, **args):
354 def showp2node(repo, ctx, templ, **args):
351 """:p2node: String. The identification hash of the changeset's second
355 """:p2node: String. The identification hash of the changeset's second
352 parent, as a 40 digit hexadecimal string. If the changeset has no second
356 parent, as a 40 digit hexadecimal string. If the changeset has no second
353 parent, all digits are 0."""
357 parent, all digits are 0."""
354 return ctx.p2().hex()
358 return ctx.p2().hex()
355
359
356 def showphase(repo, ctx, templ, **args):
360 def showphase(repo, ctx, templ, **args):
357 """:phase: String. The changeset phase name."""
361 """:phase: String. The changeset phase name."""
358 return ctx.phasestr()
362 return ctx.phasestr()
359
363
360 def showphaseidx(repo, ctx, templ, **args):
364 def showphaseidx(repo, ctx, templ, **args):
361 """:phaseidx: Integer. The changeset phase index."""
365 """:phaseidx: Integer. The changeset phase index."""
362 return ctx.phase()
366 return ctx.phase()
363
367
364 def showrev(repo, ctx, templ, **args):
368 def showrev(repo, ctx, templ, **args):
365 """:rev: Integer. The repository-local changeset revision number."""
369 """:rev: Integer. The repository-local changeset revision number."""
366 return ctx.rev()
370 return ctx.rev()
367
371
368 def showsubrepos(**args):
372 def showsubrepos(**args):
369 """:subrepos: List of strings. Updated subrepositories in the changeset."""
373 """:subrepos: List of strings. Updated subrepositories in the changeset."""
370 ctx = args['ctx']
374 ctx = args['ctx']
371 substate = ctx.substate
375 substate = ctx.substate
372 if not substate:
376 if not substate:
373 return showlist('subrepo', [], **args)
377 return showlist('subrepo', [], **args)
374 psubstate = ctx.parents()[0].substate or {}
378 psubstate = ctx.parents()[0].substate or {}
375 subrepos = []
379 subrepos = []
376 for sub in substate:
380 for sub in substate:
377 if sub not in psubstate or substate[sub] != psubstate[sub]:
381 if sub not in psubstate or substate[sub] != psubstate[sub]:
378 subrepos.append(sub) # modified or newly added in ctx
382 subrepos.append(sub) # modified or newly added in ctx
379 for sub in psubstate:
383 for sub in psubstate:
380 if sub not in substate:
384 if sub not in substate:
381 subrepos.append(sub) # removed in ctx
385 subrepos.append(sub) # removed in ctx
382 return showlist('subrepo', sorted(subrepos), **args)
386 return showlist('subrepo', sorted(subrepos), **args)
383
387
384 def shownames(namespace, **args):
388 def shownames(namespace, **args):
385 """helper method to generate a template keyword for a namespace"""
389 """helper method to generate a template keyword for a namespace"""
386 ctx = args['ctx']
390 ctx = args['ctx']
387 repo = ctx._repo
391 repo = ctx._repo
388 ns = repo.names[namespace]
392 ns = repo.names[namespace]
389 names = ns.names(repo, ctx.node())
393 names = ns.names(repo, ctx.node())
390 return showlist(ns.templatename, names, plural=namespace, **args)
394 return showlist(ns.templatename, names, plural=namespace, **args)
391
395
392 # don't remove "showtags" definition, even though namespaces will put
396 # don't remove "showtags" definition, even though namespaces will put
393 # a helper function for "tags" keyword into "keywords" map automatically,
397 # a helper function for "tags" keyword into "keywords" map automatically,
394 # because online help text is built without namespaces initialization
398 # because online help text is built without namespaces initialization
395 def showtags(**args):
399 def showtags(**args):
396 """:tags: List of strings. Any tags associated with the changeset."""
400 """:tags: List of strings. Any tags associated with the changeset."""
397 return shownames('tags', **args)
401 return shownames('tags', **args)
398
402
399 # keywords are callables like:
403 # keywords are callables like:
400 # fn(repo, ctx, templ, cache, revcache, **args)
404 # fn(repo, ctx, templ, cache, revcache, **args)
401 # with:
405 # with:
402 # repo - current repository instance
406 # repo - current repository instance
403 # ctx - the changectx being displayed
407 # ctx - the changectx being displayed
404 # templ - the templater instance
408 # templ - the templater instance
405 # cache - a cache dictionary for the whole templater run
409 # cache - a cache dictionary for the whole templater run
406 # revcache - a cache dictionary for the current revision
410 # revcache - a cache dictionary for the current revision
407 keywords = {
411 keywords = {
408 'author': showauthor,
412 'author': showauthor,
409 'bisect': showbisect,
413 'bisect': showbisect,
410 'branch': showbranch,
414 'branch': showbranch,
411 'branches': showbranches,
415 'branches': showbranches,
412 'bookmarks': showbookmarks,
416 'bookmarks': showbookmarks,
413 'children': showchildren,
417 'children': showchildren,
414 'currentbookmark': showcurrentbookmark,
418 'currentbookmark': showcurrentbookmark,
415 'date': showdate,
419 'date': showdate,
416 'desc': showdescription,
420 'desc': showdescription,
417 'diffstat': showdiffstat,
421 'diffstat': showdiffstat,
418 'extras': showextras,
422 'extras': showextras,
419 'file_adds': showfileadds,
423 'file_adds': showfileadds,
420 'file_copies': showfilecopies,
424 'file_copies': showfilecopies,
421 'file_copies_switch': showfilecopiesswitch,
425 'file_copies_switch': showfilecopiesswitch,
422 'file_dels': showfiledels,
426 'file_dels': showfiledels,
423 'file_mods': showfilemods,
427 'file_mods': showfilemods,
424 'files': showfiles,
428 'files': showfiles,
425 'latesttag': showlatesttag,
429 'latesttag': showlatesttag,
426 'latesttagdistance': showlatesttagdistance,
430 'latesttagdistance': showlatesttagdistance,
427 'manifest': showmanifest,
431 'manifest': showmanifest,
428 'node': shownode,
432 'node': shownode,
429 'p1rev': showp1rev,
433 'p1rev': showp1rev,
430 'p1node': showp1node,
434 'p1node': showp1node,
431 'p2rev': showp2rev,
435 'p2rev': showp2rev,
432 'p2node': showp2node,
436 'p2node': showp2node,
433 'phase': showphase,
437 'phase': showphase,
434 'phaseidx': showphaseidx,
438 'phaseidx': showphaseidx,
435 'rev': showrev,
439 'rev': showrev,
436 'subrepos': showsubrepos,
440 'subrepos': showsubrepos,
437 'tags': showtags,
441 'tags': showtags,
438 }
442 }
439
443
440 def _showparents(**args):
444 def _showparents(**args):
441 """:parents: List of strings. The parents of the changeset in "rev:node"
445 """:parents: List of strings. The parents of the changeset in "rev:node"
442 format. If the changeset has only one "natural" parent (the predecessor
446 format. If the changeset has only one "natural" parent (the predecessor
443 revision) nothing is shown."""
447 revision) nothing is shown."""
444 pass
448 pass
445
449
446 dockeywords = {
450 dockeywords = {
447 'parents': _showparents,
451 'parents': _showparents,
448 }
452 }
449 dockeywords.update(keywords)
453 dockeywords.update(keywords)
450 del dockeywords['branches']
454 del dockeywords['branches']
451
455
452 # tell hggettext to extract docstrings from these functions:
456 # tell hggettext to extract docstrings from these functions:
453 i18nfunctions = dockeywords.values()
457 i18nfunctions = dockeywords.values()
General Comments 0
You need to be logged in to leave comments. Login now