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 'bookmark: %s\n' |
116 b'bookmark: %s\n' |
117 'branch: %s\n' |
117 b'branch: %s\n' |
118 'changeset: %s\n' |
118 b'changeset: %s\n' |
119 'copies: %s\n' |
119 b'copies: %s\n' |
120 'date: %s\n' |
120 b'date: %s\n' |
121 'extra: %s=%s\n' |
121 b'extra: %s=%s\n' |
122 'files+: %s\n' |
122 b'files+: %s\n' |
123 'files-: %s\n' |
123 b'files-: %s\n' |
124 'files: %s\n' |
124 b'files: %s\n' |
125 'instability: %s\n' |
125 b'instability: %s\n' |
126 'manifest: %s\n' |
126 b'manifest: %s\n' |
127 'obsolete: %s\n' |
127 b'obsolete: %s\n' |
128 'parent: %s\n' |
128 b'parent: %s\n' |
129 'phase: %s\n' |
129 b'phase: %s\n' |
130 'summary: %s\n' |
130 b'summary: %s\n' |
131 'tag: %s\n' |
131 b'tag: %s\n' |
132 'user: %s\n' |
132 b'user: %s\n' |
133 ) |
133 ) |
134 return dict( |
134 return dict( |
135 zip( |
135 zip( |
136 [s.split(':', 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 = '{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 'parent': _changeidtmpl + ' ', |
147 b'parent': _changeidtmpl + b' ', |
148 'manifest': _changeidtmpl, |
148 b'manifest': _changeidtmpl, |
149 'file_copy': '{name} ({source})', |
149 b'file_copy': b'{name} ({source})', |
150 'envvar': '{key}={value}', |
150 b'envvar': b'{key}={value}', |
151 'extra': '{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['filecopy'] = defaulttempl['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('author', requires={'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('bisect', requires={'repo', '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, 'repo') |
170 repo = context.resource(mapping, b'repo') |
171 ctx = context.resource(mapping, '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('branch', requires={'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, 'ctx') |
180 ctx = context.resource(mapping, b'ctx') |
181 return ctx.branch() |
181 return ctx.branch() |
182 |
182 |
183 |
183 |
184 @templatekeyword('branches', requires={'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, 'ctx') |
190 ctx = context.resource(mapping, b'ctx') |
191 branch = ctx.branch() |
191 branch = ctx.branch() |
192 if branch != 'default': |
192 if branch != b'default': |
193 return compatlist( |
193 return compatlist( |
194 context, mapping, 'branch', [branch], plural='branches' |
194 context, mapping, b'branch', [branch], plural=b'branches' |
195 ) |
195 ) |
196 return compatlist(context, mapping, 'branch', [], plural='branches') |
196 return compatlist(context, mapping, b'branch', [], plural=b'branches') |
197 |
197 |
198 |
198 |
199 @templatekeyword('bookmarks', requires={'repo', '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, 'repo') |
204 repo = context.resource(mapping, b'repo') |
205 ctx = context.resource(mapping, '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: {'bookmark': v, 'active': active, 'current': active} |
208 makemap = lambda v: {b'bookmark': v, b'active': active, b'current': active} |
209 f = _showcompatlist(context, mapping, '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('children', requires={'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, 'ctx') |
216 ctx = context.resource(mapping, b'ctx') |
217 childrevs = ['%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(context, mapping, 'children', childrevs, element='child') |
218 return compatlist( |
|
219 context, mapping, b'children', childrevs, element=b'child' |
|
220 ) |
219 |
221 |
220 |
222 |
221 # Deprecated, but kept alive for help generation a purpose. |
223 # Deprecated, but kept alive for help generation a purpose. |
222 @templatekeyword('currentbookmark', requires={'repo', 'ctx'}) |
224 @templatekeyword(b'currentbookmark', requires={b'repo', b'ctx'}) |
223 def showcurrentbookmark(context, mapping): |
225 def showcurrentbookmark(context, mapping): |
224 """String. The active bookmark, if it is associated with the changeset. |
226 """String. The active bookmark, if it is associated with the changeset. |
225 (DEPRECATED)""" |
227 (DEPRECATED)""" |
226 return showactivebookmark(context, mapping) |
228 return showactivebookmark(context, mapping) |
227 |
229 |
228 |
230 |
229 @templatekeyword('activebookmark', requires={'repo', 'ctx'}) |
231 @templatekeyword(b'activebookmark', requires={b'repo', b'ctx'}) |
230 def showactivebookmark(context, mapping): |
232 def showactivebookmark(context, mapping): |
231 """String. The active bookmark, if it is associated with the changeset.""" |
233 """String. The active bookmark, if it is associated with the changeset.""" |
232 repo = context.resource(mapping, 'repo') |
234 repo = context.resource(mapping, b'repo') |
233 ctx = context.resource(mapping, 'ctx') |
235 ctx = context.resource(mapping, b'ctx') |
234 active = repo._activebookmark |
236 active = repo._activebookmark |
235 if active and active in ctx.bookmarks(): |
237 if active and active in ctx.bookmarks(): |
236 return active |
238 return active |
237 return '' |
239 return b'' |
238 |
240 |
239 |
241 |
240 @templatekeyword('date', requires={'ctx'}) |
242 @templatekeyword(b'date', requires={b'ctx'}) |
241 def showdate(context, mapping): |
243 def showdate(context, mapping): |
242 """Date information. The date when the changeset was committed.""" |
244 """Date information. The date when the changeset was committed.""" |
243 ctx = context.resource(mapping, 'ctx') |
245 ctx = context.resource(mapping, b'ctx') |
244 # the default string format is '<float(unixtime)><tzoffset>' because |
246 # the default string format is '<float(unixtime)><tzoffset>' because |
245 # python-hglib splits date at decimal separator. |
247 # python-hglib splits date at decimal separator. |
246 return templateutil.date(ctx.date(), showfmt='%d.0%d') |
248 return templateutil.date(ctx.date(), showfmt=b'%d.0%d') |
247 |
249 |
248 |
250 |
249 @templatekeyword('desc', requires={'ctx'}) |
251 @templatekeyword(b'desc', requires={b'ctx'}) |
250 def showdescription(context, mapping): |
252 def showdescription(context, mapping): |
251 """String. The text of the changeset description.""" |
253 """String. The text of the changeset description.""" |
252 ctx = context.resource(mapping, 'ctx') |
254 ctx = context.resource(mapping, b'ctx') |
253 s = ctx.description() |
255 s = ctx.description() |
254 if isinstance(s, encoding.localstr): |
256 if isinstance(s, encoding.localstr): |
255 # try hard to preserve utf-8 bytes |
257 # try hard to preserve utf-8 bytes |
256 return encoding.tolocal(encoding.fromlocal(s).strip()) |
258 return encoding.tolocal(encoding.fromlocal(s).strip()) |
257 elif isinstance(s, encoding.safelocalstr): |
259 elif isinstance(s, encoding.safelocalstr): |
258 return encoding.safelocalstr(s.strip()) |
260 return encoding.safelocalstr(s.strip()) |
259 else: |
261 else: |
260 return s.strip() |
262 return s.strip() |
261 |
263 |
262 |
264 |
263 @templatekeyword('diffstat', requires={'ui', 'ctx'}) |
265 @templatekeyword(b'diffstat', requires={b'ui', b'ctx'}) |
264 def showdiffstat(context, mapping): |
266 def showdiffstat(context, mapping): |
265 """String. Statistics of changes with the following format: |
267 """String. Statistics of changes with the following format: |
266 "modified files: +added/-removed lines" |
268 "modified files: +added/-removed lines" |
267 """ |
269 """ |
268 ui = context.resource(mapping, 'ui') |
270 ui = context.resource(mapping, b'ui') |
269 ctx = context.resource(mapping, 'ctx') |
271 ctx = context.resource(mapping, b'ctx') |
270 diffopts = diffutil.diffallopts(ui, {'noprefix': False}) |
272 diffopts = diffutil.diffallopts(ui, {b'noprefix': False}) |
271 diff = ctx.diff(opts=diffopts) |
273 diff = ctx.diff(opts=diffopts) |
272 stats = patch.diffstatdata(util.iterlines(diff)) |
274 stats = patch.diffstatdata(util.iterlines(diff)) |
273 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats) |
275 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats) |
274 return '%d: +%d/-%d' % (len(stats), adds, removes) |
276 return b'%d: +%d/-%d' % (len(stats), adds, removes) |
275 |
277 |
276 |
278 |
277 @templatekeyword('envvars', requires={'ui'}) |
279 @templatekeyword(b'envvars', requires={b'ui'}) |
278 def showenvvars(context, mapping): |
280 def showenvvars(context, mapping): |
279 """A dictionary of environment variables. (EXPERIMENTAL)""" |
281 """A dictionary of environment variables. (EXPERIMENTAL)""" |
280 ui = context.resource(mapping, 'ui') |
282 ui = context.resource(mapping, b'ui') |
281 env = ui.exportableenviron() |
283 env = ui.exportableenviron() |
282 env = util.sortdict((k, env[k]) for k in sorted(env)) |
284 env = util.sortdict((k, env[k]) for k in sorted(env)) |
283 return compatdict(context, mapping, 'envvar', env, plural='envvars') |
285 return compatdict(context, mapping, b'envvar', env, plural=b'envvars') |
284 |
286 |
285 |
287 |
286 @templatekeyword('extras', requires={'ctx'}) |
288 @templatekeyword(b'extras', requires={b'ctx'}) |
287 def showextras(context, mapping): |
289 def showextras(context, mapping): |
288 """List of dicts with key, value entries of the 'extras' |
290 """List of dicts with key, value entries of the 'extras' |
289 field of this changeset.""" |
291 field of this changeset.""" |
290 ctx = context.resource(mapping, 'ctx') |
292 ctx = context.resource(mapping, b'ctx') |
291 extras = ctx.extra() |
293 extras = ctx.extra() |
292 extras = util.sortdict((k, extras[k]) for k in sorted(extras)) |
294 extras = util.sortdict((k, extras[k]) for k in sorted(extras)) |
293 makemap = lambda k: {'key': k, 'value': extras[k]} |
295 makemap = lambda k: {b'key': k, b'value': extras[k]} |
294 c = [makemap(k) for k in extras] |
296 c = [makemap(k) for k in extras] |
295 f = _showcompatlist(context, mapping, 'extra', c, plural='extras') |
297 f = _showcompatlist(context, mapping, b'extra', c, plural=b'extras') |
296 return _hybrid( |
298 return _hybrid( |
297 f, |
299 f, |
298 extras, |
300 extras, |
299 makemap, |
301 makemap, |
300 lambda k: '%s=%s' % (k, stringutil.escapestr(extras[k])), |
302 lambda k: b'%s=%s' % (k, stringutil.escapestr(extras[k])), |
301 ) |
303 ) |
302 |
304 |
303 |
305 |
304 def _getfilestatus(context, mapping, listall=False): |
306 def _getfilestatus(context, mapping, listall=False): |
305 ctx = context.resource(mapping, 'ctx') |
307 ctx = context.resource(mapping, b'ctx') |
306 revcache = context.resource(mapping, 'revcache') |
308 revcache = context.resource(mapping, b'revcache') |
307 if 'filestatus' not in revcache or revcache['filestatusall'] < listall: |
309 if b'filestatus' not in revcache or revcache[b'filestatusall'] < listall: |
308 stat = ctx.p1().status( |
310 stat = ctx.p1().status( |
309 ctx, listignored=listall, listclean=listall, listunknown=listall |
311 ctx, listignored=listall, listclean=listall, listunknown=listall |
310 ) |
312 ) |
311 revcache['filestatus'] = stat |
313 revcache[b'filestatus'] = stat |
312 revcache['filestatusall'] = listall |
314 revcache[b'filestatusall'] = listall |
313 return revcache['filestatus'] |
315 return revcache[b'filestatus'] |
314 |
316 |
315 |
317 |
316 def _getfilestatusmap(context, mapping, listall=False): |
318 def _getfilestatusmap(context, mapping, listall=False): |
317 revcache = context.resource(mapping, 'revcache') |
319 revcache = context.resource(mapping, b'revcache') |
318 if 'filestatusmap' not in revcache or revcache['filestatusall'] < listall: |
320 if b'filestatusmap' not in revcache or revcache[b'filestatusall'] < listall: |
319 stat = _getfilestatus(context, mapping, listall=listall) |
321 stat = _getfilestatus(context, mapping, listall=listall) |
320 revcache['filestatusmap'] = statmap = {} |
322 revcache[b'filestatusmap'] = statmap = {} |
321 for char, files in zip(pycompat.iterbytestr('MAR!?IC'), stat): |
323 for char, files in zip(pycompat.iterbytestr(b'MAR!?IC'), stat): |
322 statmap.update((f, char) for f in files) |
324 statmap.update((f, char) for f in files) |
323 return revcache['filestatusmap'] # {path: statchar} |
325 return revcache[b'filestatusmap'] # {path: statchar} |
324 |
326 |
325 |
327 |
326 @templatekeyword('file_copies', requires={'repo', 'ctx', 'cache', 'revcache'}) |
328 @templatekeyword( |
|
329 b'file_copies', requires={b'repo', b'ctx', b'cache', b'revcache'} |
|
330 ) |
327 def showfilecopies(context, mapping): |
331 def showfilecopies(context, mapping): |
328 """List of strings. Files copied in this changeset with |
332 """List of strings. Files copied in this changeset with |
329 their sources. |
333 their sources. |
330 """ |
334 """ |
331 repo = context.resource(mapping, 'repo') |
335 repo = context.resource(mapping, b'repo') |
332 ctx = context.resource(mapping, 'ctx') |
336 ctx = context.resource(mapping, b'ctx') |
333 cache = context.resource(mapping, 'cache') |
337 cache = context.resource(mapping, b'cache') |
334 copies = context.resource(mapping, 'revcache').get('copies') |
338 copies = context.resource(mapping, b'revcache').get(b'copies') |
335 if copies is None: |
339 if copies is None: |
336 if 'getcopies' not in cache: |
340 if b'getcopies' not in cache: |
337 cache['getcopies'] = scmutil.getcopiesfn(repo) |
341 cache[b'getcopies'] = scmutil.getcopiesfn(repo) |
338 getcopies = cache['getcopies'] |
342 getcopies = cache[b'getcopies'] |
339 copies = getcopies(ctx) |
343 copies = getcopies(ctx) |
340 return templateutil.compatfilecopiesdict( |
344 return templateutil.compatfilecopiesdict( |
341 context, mapping, 'file_copy', copies |
345 context, mapping, b'file_copy', copies |
342 ) |
346 ) |
343 |
347 |
344 |
348 |
345 # showfilecopiesswitch() displays file copies only if copy records are |
349 # showfilecopiesswitch() displays file copies only if copy records are |
346 # provided before calling the templater, usually with a --copies |
350 # provided before calling the templater, usually with a --copies |
347 # command line switch. |
351 # command line switch. |
348 @templatekeyword('file_copies_switch', requires={'revcache'}) |
352 @templatekeyword(b'file_copies_switch', requires={b'revcache'}) |
349 def showfilecopiesswitch(context, mapping): |
353 def showfilecopiesswitch(context, mapping): |
350 """List of strings. Like "file_copies" but displayed |
354 """List of strings. Like "file_copies" but displayed |
351 only if the --copied switch is set. |
355 only if the --copied switch is set. |
352 """ |
356 """ |
353 copies = context.resource(mapping, 'revcache').get('copies') or [] |
357 copies = context.resource(mapping, b'revcache').get(b'copies') or [] |
354 return templateutil.compatfilecopiesdict( |
358 return templateutil.compatfilecopiesdict( |
355 context, mapping, 'file_copy', copies |
359 context, mapping, b'file_copy', copies |
356 ) |
360 ) |
357 |
361 |
358 |
362 |
359 @templatekeyword('file_adds', requires={'ctx', 'revcache'}) |
363 @templatekeyword(b'file_adds', requires={b'ctx', b'revcache'}) |
360 def showfileadds(context, mapping): |
364 def showfileadds(context, mapping): |
361 """List of strings. Files added by this changeset.""" |
365 """List of strings. Files added by this changeset.""" |
362 ctx = context.resource(mapping, 'ctx') |
366 ctx = context.resource(mapping, b'ctx') |
363 return templateutil.compatfileslist( |
367 return templateutil.compatfileslist( |
364 context, mapping, 'file_add', ctx.filesadded() |
368 context, mapping, b'file_add', ctx.filesadded() |
365 ) |
369 ) |
366 |
370 |
367 |
371 |
368 @templatekeyword('file_dels', requires={'ctx', 'revcache'}) |
372 @templatekeyword(b'file_dels', requires={b'ctx', b'revcache'}) |
369 def showfiledels(context, mapping): |
373 def showfiledels(context, mapping): |
370 """List of strings. Files removed by this changeset.""" |
374 """List of strings. Files removed by this changeset.""" |
371 ctx = context.resource(mapping, 'ctx') |
375 ctx = context.resource(mapping, b'ctx') |
372 return templateutil.compatfileslist( |
376 return templateutil.compatfileslist( |
373 context, mapping, 'file_del', ctx.filesremoved() |
377 context, mapping, b'file_del', ctx.filesremoved() |
374 ) |
378 ) |
375 |
379 |
376 |
380 |
377 @templatekeyword('file_mods', requires={'ctx', 'revcache'}) |
381 @templatekeyword(b'file_mods', requires={b'ctx', b'revcache'}) |
378 def showfilemods(context, mapping): |
382 def showfilemods(context, mapping): |
379 """List of strings. Files modified by this changeset.""" |
383 """List of strings. Files modified by this changeset.""" |
380 ctx = context.resource(mapping, 'ctx') |
384 ctx = context.resource(mapping, b'ctx') |
381 return templateutil.compatfileslist( |
385 return templateutil.compatfileslist( |
382 context, mapping, 'file_mod', ctx.filesmodified() |
386 context, mapping, b'file_mod', ctx.filesmodified() |
383 ) |
387 ) |
384 |
388 |
385 |
389 |
386 @templatekeyword('files', requires={'ctx'}) |
390 @templatekeyword(b'files', requires={b'ctx'}) |
387 def showfiles(context, mapping): |
391 def showfiles(context, mapping): |
388 """List of strings. All files modified, added, or removed by this |
392 """List of strings. All files modified, added, or removed by this |
389 changeset. |
393 changeset. |
390 """ |
394 """ |
391 ctx = context.resource(mapping, 'ctx') |
395 ctx = context.resource(mapping, b'ctx') |
392 return templateutil.compatfileslist(context, mapping, 'file', ctx.files()) |
396 return templateutil.compatfileslist(context, mapping, b'file', ctx.files()) |
393 |
397 |
394 |
398 |
395 @templatekeyword('graphnode', requires={'repo', 'ctx'}) |
399 @templatekeyword(b'graphnode', requires={b'repo', b'ctx'}) |
396 def showgraphnode(context, mapping): |
400 def showgraphnode(context, mapping): |
397 """String. The character representing the changeset node in an ASCII |
401 """String. The character representing the changeset node in an ASCII |
398 revision graph.""" |
402 revision graph.""" |
399 repo = context.resource(mapping, 'repo') |
403 repo = context.resource(mapping, b'repo') |
400 ctx = context.resource(mapping, 'ctx') |
404 ctx = context.resource(mapping, b'ctx') |
401 return getgraphnode(repo, ctx) |
405 return getgraphnode(repo, ctx) |
402 |
406 |
403 |
407 |
404 def getgraphnode(repo, ctx): |
408 def getgraphnode(repo, ctx): |
405 return getgraphnodecurrent(repo, ctx) or getgraphnodesymbol(ctx) |
409 return getgraphnodecurrent(repo, ctx) or getgraphnodesymbol(ctx) |
455 |
459 |
456 # latesttag[0] is an implementation detail for sorting csets on different |
460 # latesttag[0] is an implementation detail for sorting csets on different |
457 # branches in a stable manner- it is the date the tagged cset was created, |
461 # branches in a stable manner- it is the date the tagged cset was created, |
458 # not the date the tag was created. Therefore it isn't made visible here. |
462 # not the date the tag was created. Therefore it isn't made visible here. |
459 makemap = lambda v: { |
463 makemap = lambda v: { |
460 'changes': _showchangessincetag, |
464 b'changes': _showchangessincetag, |
461 'distance': latesttags[1], |
465 b'distance': latesttags[1], |
462 'latesttag': v, # BC with {latesttag % '{latesttag}'} |
466 b'latesttag': v, # BC with {latesttag % '{latesttag}'} |
463 'tag': v, |
467 b'tag': v, |
464 } |
468 } |
465 |
469 |
466 tags = latesttags[2] |
470 tags = latesttags[2] |
467 f = _showcompatlist(context, mapping, 'latesttag', tags, separator=':') |
471 f = _showcompatlist(context, mapping, b'latesttag', tags, separator=b':') |
468 return _hybrid(f, tags, makemap, pycompat.identity) |
472 return _hybrid(f, tags, makemap, pycompat.identity) |
469 |
473 |
470 |
474 |
471 @templatekeyword('latesttagdistance', requires={'repo', 'ctx', 'cache'}) |
475 @templatekeyword(b'latesttagdistance', requires={b'repo', b'ctx', b'cache'}) |
472 def showlatesttagdistance(context, mapping): |
476 def showlatesttagdistance(context, mapping): |
473 """Integer. Longest path to the latest tag.""" |
477 """Integer. Longest path to the latest tag.""" |
474 return getlatesttags(context, mapping)[1] |
478 return getlatesttags(context, mapping)[1] |
475 |
479 |
476 |
480 |
477 @templatekeyword('changessincelatesttag', requires={'repo', 'ctx', 'cache'}) |
481 @templatekeyword(b'changessincelatesttag', requires={b'repo', b'ctx', b'cache'}) |
478 def showchangessincelatesttag(context, mapping): |
482 def showchangessincelatesttag(context, mapping): |
479 """Integer. All ancestors not in the latest tag.""" |
483 """Integer. All ancestors not in the latest tag.""" |
480 tag = getlatesttags(context, mapping)[2][0] |
484 tag = getlatesttags(context, mapping)[2][0] |
481 mapping = context.overlaymap(mapping, {'tag': tag}) |
485 mapping = context.overlaymap(mapping, {b'tag': tag}) |
482 return _showchangessincetag(context, mapping) |
486 return _showchangessincetag(context, mapping) |
483 |
487 |
484 |
488 |
485 def _showchangessincetag(context, mapping): |
489 def _showchangessincetag(context, mapping): |
486 repo = context.resource(mapping, 'repo') |
490 repo = context.resource(mapping, b'repo') |
487 ctx = context.resource(mapping, 'ctx') |
491 ctx = context.resource(mapping, b'ctx') |
488 offset = 0 |
492 offset = 0 |
489 revs = [ctx.rev()] |
493 revs = [ctx.rev()] |
490 tag = context.symbol(mapping, 'tag') |
494 tag = context.symbol(mapping, b'tag') |
491 |
495 |
492 # The only() revset doesn't currently support wdir() |
496 # The only() revset doesn't currently support wdir() |
493 if ctx.rev() is None: |
497 if ctx.rev() is None: |
494 offset = 1 |
498 offset = 1 |
495 revs = [p.rev() for p in ctx.parents()] |
499 revs = [p.rev() for p in ctx.parents()] |
496 |
500 |
497 return len(repo.revs('only(%ld, %s)', revs, tag)) + offset |
501 return len(repo.revs(b'only(%ld, %s)', revs, tag)) + offset |
498 |
502 |
499 |
503 |
500 # teach templater latesttags.changes is switched to (context, mapping) API |
504 # teach templater latesttags.changes is switched to (context, mapping) API |
501 _showchangessincetag._requires = {'repo', 'ctx'} |
505 _showchangessincetag._requires = {b'repo', b'ctx'} |
502 |
506 |
503 |
507 |
504 @templatekeyword('manifest', requires={'repo', 'ctx'}) |
508 @templatekeyword(b'manifest', requires={b'repo', b'ctx'}) |
505 def showmanifest(context, mapping): |
509 def showmanifest(context, mapping): |
506 repo = context.resource(mapping, 'repo') |
510 repo = context.resource(mapping, b'repo') |
507 ctx = context.resource(mapping, 'ctx') |
511 ctx = context.resource(mapping, b'ctx') |
508 mnode = ctx.manifestnode() |
512 mnode = ctx.manifestnode() |
509 if mnode is None: |
513 if mnode is None: |
510 mnode = wdirid |
514 mnode = wdirid |
511 mrev = wdirrev |
515 mrev = wdirrev |
512 else: |
516 else: |
513 mrev = repo.manifestlog.rev(mnode) |
517 mrev = repo.manifestlog.rev(mnode) |
514 mhex = hex(mnode) |
518 mhex = hex(mnode) |
515 mapping = context.overlaymap(mapping, {'rev': mrev, 'node': mhex}) |
519 mapping = context.overlaymap(mapping, {b'rev': mrev, b'node': mhex}) |
516 f = context.process('manifest', mapping) |
520 f = context.process(b'manifest', mapping) |
517 return templateutil.hybriditem( |
521 return templateutil.hybriditem( |
518 f, None, f, lambda x: {'rev': mrev, 'node': mhex} |
522 f, None, f, lambda x: {b'rev': mrev, b'node': mhex} |
519 ) |
523 ) |
520 |
524 |
521 |
525 |
522 @templatekeyword('obsfate', requires={'ui', 'repo', 'ctx'}) |
526 @templatekeyword(b'obsfate', requires={b'ui', b'repo', b'ctx'}) |
523 def showobsfate(context, mapping): |
527 def showobsfate(context, mapping): |
524 # this function returns a list containing pre-formatted obsfate strings. |
528 # this function returns a list containing pre-formatted obsfate strings. |
525 # |
529 # |
526 # This function will be replaced by templates fragments when we will have |
530 # This function will be replaced by templates fragments when we will have |
527 # the verbosity templatekw available. |
531 # the verbosity templatekw available. |
528 succsandmarkers = showsuccsandmarkers(context, mapping) |
532 succsandmarkers = showsuccsandmarkers(context, mapping) |
529 |
533 |
530 ui = context.resource(mapping, 'ui') |
534 ui = context.resource(mapping, b'ui') |
531 repo = context.resource(mapping, 'repo') |
535 repo = context.resource(mapping, b'repo') |
532 values = [] |
536 values = [] |
533 |
537 |
534 for x in succsandmarkers.tovalue(context, mapping): |
538 for x in succsandmarkers.tovalue(context, mapping): |
535 v = obsutil.obsfateprinter( |
539 v = obsutil.obsfateprinter( |
536 ui, repo, x['successors'], x['markers'], scmutil.formatchangeid |
540 ui, repo, x[b'successors'], x[b'markers'], scmutil.formatchangeid |
537 ) |
541 ) |
538 values.append(v) |
542 values.append(v) |
539 |
543 |
540 return compatlist(context, mapping, "fate", values) |
544 return compatlist(context, mapping, b"fate", values) |
541 |
545 |
542 |
546 |
543 def shownames(context, mapping, namespace): |
547 def shownames(context, mapping, namespace): |
544 """helper method to generate a template keyword for a namespace""" |
548 """helper method to generate a template keyword for a namespace""" |
545 repo = context.resource(mapping, 'repo') |
549 repo = context.resource(mapping, b'repo') |
546 ctx = context.resource(mapping, 'ctx') |
550 ctx = context.resource(mapping, b'ctx') |
547 ns = repo.names[namespace] |
551 ns = repo.names[namespace] |
548 names = ns.names(repo, ctx.node()) |
552 names = ns.names(repo, ctx.node()) |
549 return compatlist( |
553 return compatlist( |
550 context, mapping, ns.templatename, names, plural=namespace |
554 context, mapping, ns.templatename, names, plural=namespace |
551 ) |
555 ) |
552 |
556 |
553 |
557 |
554 @templatekeyword('namespaces', requires={'repo', 'ctx'}) |
558 @templatekeyword(b'namespaces', requires={b'repo', b'ctx'}) |
555 def shownamespaces(context, mapping): |
559 def shownamespaces(context, mapping): |
556 """Dict of lists. Names attached to this changeset per |
560 """Dict of lists. Names attached to this changeset per |
557 namespace.""" |
561 namespace.""" |
558 repo = context.resource(mapping, 'repo') |
562 repo = context.resource(mapping, b'repo') |
559 ctx = context.resource(mapping, 'ctx') |
563 ctx = context.resource(mapping, b'ctx') |
560 |
564 |
561 namespaces = util.sortdict() |
565 namespaces = util.sortdict() |
562 |
566 |
563 def makensmapfn(ns): |
567 def makensmapfn(ns): |
564 # 'name' for iterating over namespaces, templatename for local reference |
568 # 'name' for iterating over namespaces, templatename for local reference |
565 return lambda v: {'name': v, ns.templatename: v} |
569 return lambda v: {b'name': v, ns.templatename: v} |
566 |
570 |
567 for k, ns in repo.names.iteritems(): |
571 for k, ns in repo.names.iteritems(): |
568 names = ns.names(repo, ctx.node()) |
572 names = ns.names(repo, ctx.node()) |
569 f = _showcompatlist(context, mapping, 'name', names) |
573 f = _showcompatlist(context, mapping, b'name', names) |
570 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity) |
574 namespaces[k] = _hybrid(f, names, makensmapfn(ns), pycompat.identity) |
571 |
575 |
572 f = _showcompatlist(context, mapping, 'namespace', list(namespaces)) |
576 f = _showcompatlist(context, mapping, b'namespace', list(namespaces)) |
573 |
577 |
574 def makemap(ns): |
578 def makemap(ns): |
575 return { |
579 return { |
576 'namespace': ns, |
580 b'namespace': ns, |
577 'names': namespaces[ns], |
581 b'names': namespaces[ns], |
578 'builtin': repo.names[ns].builtin, |
582 b'builtin': repo.names[ns].builtin, |
579 'colorname': repo.names[ns].colorname, |
583 b'colorname': repo.names[ns].colorname, |
580 } |
584 } |
581 |
585 |
582 return _hybrid(f, namespaces, makemap, pycompat.identity) |
586 return _hybrid(f, namespaces, makemap, pycompat.identity) |
583 |
587 |
584 |
588 |
585 @templatekeyword('negrev', requires={'repo', 'ctx'}) |
589 @templatekeyword(b'negrev', requires={b'repo', b'ctx'}) |
586 def shownegrev(context, mapping): |
590 def shownegrev(context, mapping): |
587 """Integer. The repository-local changeset negative revision number, |
591 """Integer. The repository-local changeset negative revision number, |
588 which counts in the opposite direction.""" |
592 which counts in the opposite direction.""" |
589 ctx = context.resource(mapping, 'ctx') |
593 ctx = context.resource(mapping, b'ctx') |
590 rev = ctx.rev() |
594 rev = ctx.rev() |
591 if rev is None or rev < 0: # wdir() or nullrev? |
595 if rev is None or rev < 0: # wdir() or nullrev? |
592 return None |
596 return None |
593 repo = context.resource(mapping, 'repo') |
597 repo = context.resource(mapping, b'repo') |
594 return rev - len(repo) |
598 return rev - len(repo) |
595 |
599 |
596 |
600 |
597 @templatekeyword('node', requires={'ctx'}) |
601 @templatekeyword(b'node', requires={b'ctx'}) |
598 def shownode(context, mapping): |
602 def shownode(context, mapping): |
599 """String. The changeset identification hash, as a 40 hexadecimal |
603 """String. The changeset identification hash, as a 40 hexadecimal |
600 digit string. |
604 digit string. |
601 """ |
605 """ |
602 ctx = context.resource(mapping, 'ctx') |
606 ctx = context.resource(mapping, b'ctx') |
603 return ctx.hex() |
607 return ctx.hex() |
604 |
608 |
605 |
609 |
606 @templatekeyword('obsolete', requires={'ctx'}) |
610 @templatekeyword(b'obsolete', requires={b'ctx'}) |
607 def showobsolete(context, mapping): |
611 def showobsolete(context, mapping): |
608 """String. Whether the changeset is obsolete. (EXPERIMENTAL)""" |
612 """String. Whether the changeset is obsolete. (EXPERIMENTAL)""" |
609 ctx = context.resource(mapping, 'ctx') |
613 ctx = context.resource(mapping, b'ctx') |
610 if ctx.obsolete(): |
614 if ctx.obsolete(): |
611 return 'obsolete' |
615 return b'obsolete' |
612 return '' |
616 return b'' |
613 |
617 |
614 |
618 |
615 @templatekeyword('path', requires={'fctx'}) |
619 @templatekeyword(b'path', requires={b'fctx'}) |
616 def showpath(context, mapping): |
620 def showpath(context, mapping): |
617 """String. Repository-absolute path of the current file. (EXPERIMENTAL)""" |
621 """String. Repository-absolute path of the current file. (EXPERIMENTAL)""" |
618 fctx = context.resource(mapping, 'fctx') |
622 fctx = context.resource(mapping, b'fctx') |
619 return fctx.path() |
623 return fctx.path() |
620 |
624 |
621 |
625 |
622 @templatekeyword('peerurls', requires={'repo'}) |
626 @templatekeyword(b'peerurls', requires={b'repo'}) |
623 def showpeerurls(context, mapping): |
627 def showpeerurls(context, mapping): |
624 """A dictionary of repository locations defined in the [paths] section |
628 """A dictionary of repository locations defined in the [paths] section |
625 of your configuration file.""" |
629 of your configuration file.""" |
626 repo = context.resource(mapping, 'repo') |
630 repo = context.resource(mapping, b'repo') |
627 # see commands.paths() for naming of dictionary keys |
631 # see commands.paths() for naming of dictionary keys |
628 paths = repo.ui.paths |
632 paths = repo.ui.paths |
629 urls = util.sortdict((k, p.rawloc) for k, p in sorted(paths.iteritems())) |
633 urls = util.sortdict((k, p.rawloc) for k, p in sorted(paths.iteritems())) |
630 |
634 |
631 def makemap(k): |
635 def makemap(k): |
632 p = paths[k] |
636 p = paths[k] |
633 d = {'name': k, 'url': p.rawloc} |
637 d = {b'name': k, b'url': p.rawloc} |
634 d.update((o, v) for o, v in sorted(p.suboptions.iteritems())) |
638 d.update((o, v) for o, v in sorted(p.suboptions.iteritems())) |
635 return d |
639 return d |
636 |
640 |
637 return _hybrid(None, urls, makemap, lambda k: '%s=%s' % (k, urls[k])) |
641 return _hybrid(None, urls, makemap, lambda k: b'%s=%s' % (k, urls[k])) |
638 |
642 |
639 |
643 |
640 @templatekeyword("predecessors", requires={'repo', 'ctx'}) |
644 @templatekeyword(b"predecessors", requires={b'repo', b'ctx'}) |
641 def showpredecessors(context, mapping): |
645 def showpredecessors(context, mapping): |
642 """Returns the list of the closest visible predecessors. (EXPERIMENTAL)""" |
646 """Returns the list of the closest visible predecessors. (EXPERIMENTAL)""" |
643 repo = context.resource(mapping, 'repo') |
647 repo = context.resource(mapping, b'repo') |
644 ctx = context.resource(mapping, 'ctx') |
648 ctx = context.resource(mapping, b'ctx') |
645 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node())) |
649 predecessors = sorted(obsutil.closestpredecessors(repo, ctx.node())) |
646 predecessors = pycompat.maplist(hex, predecessors) |
650 predecessors = pycompat.maplist(hex, predecessors) |
647 |
651 |
648 return _hybrid( |
652 return _hybrid( |
649 None, |
653 None, |
650 predecessors, |
654 predecessors, |
651 lambda x: {'ctx': repo[x]}, |
655 lambda x: {b'ctx': repo[x]}, |
652 lambda x: scmutil.formatchangeid(repo[x]), |
656 lambda x: scmutil.formatchangeid(repo[x]), |
653 ) |
657 ) |
654 |
658 |
655 |
659 |
656 @templatekeyword('reporoot', requires={'repo'}) |
660 @templatekeyword(b'reporoot', requires={b'repo'}) |
657 def showreporoot(context, mapping): |
661 def showreporoot(context, mapping): |
658 """String. The root directory of the current repository.""" |
662 """String. The root directory of the current repository.""" |
659 repo = context.resource(mapping, 'repo') |
663 repo = context.resource(mapping, b'repo') |
660 return repo.root |
664 return repo.root |
661 |
665 |
662 |
666 |
663 @templatekeyword('size', requires={'fctx'}) |
667 @templatekeyword(b'size', requires={b'fctx'}) |
664 def showsize(context, mapping): |
668 def showsize(context, mapping): |
665 """Integer. Size of the current file in bytes. (EXPERIMENTAL)""" |
669 """Integer. Size of the current file in bytes. (EXPERIMENTAL)""" |
666 fctx = context.resource(mapping, 'fctx') |
670 fctx = context.resource(mapping, b'fctx') |
667 return fctx.size() |
671 return fctx.size() |
668 |
672 |
669 |
673 |
670 # requires 'fctx' to denote {status} depends on (ctx, path) pair |
674 # requires 'fctx' to denote {status} depends on (ctx, path) pair |
671 @templatekeyword('status', requires={'ctx', 'fctx', 'revcache'}) |
675 @templatekeyword(b'status', requires={b'ctx', b'fctx', b'revcache'}) |
672 def showstatus(context, mapping): |
676 def showstatus(context, mapping): |
673 """String. Status code of the current file. (EXPERIMENTAL)""" |
677 """String. Status code of the current file. (EXPERIMENTAL)""" |
674 path = templateutil.runsymbol(context, mapping, 'path') |
678 path = templateutil.runsymbol(context, mapping, b'path') |
675 path = templateutil.stringify(context, mapping, path) |
679 path = templateutil.stringify(context, mapping, path) |
676 if not path: |
680 if not path: |
677 return |
681 return |
678 statmap = _getfilestatusmap(context, mapping) |
682 statmap = _getfilestatusmap(context, mapping) |
679 if path not in statmap: |
683 if path not in statmap: |
680 statmap = _getfilestatusmap(context, mapping, listall=True) |
684 statmap = _getfilestatusmap(context, mapping, listall=True) |
681 return statmap.get(path) |
685 return statmap.get(path) |
682 |
686 |
683 |
687 |
684 @templatekeyword("successorssets", requires={'repo', 'ctx'}) |
688 @templatekeyword(b"successorssets", requires={b'repo', b'ctx'}) |
685 def showsuccessorssets(context, mapping): |
689 def showsuccessorssets(context, mapping): |
686 """Returns a string of sets of successors for a changectx. Format used |
690 """Returns a string of sets of successors for a changectx. Format used |
687 is: [ctx1, ctx2], [ctx3] if ctx has been split into ctx1 and ctx2 |
691 is: [ctx1, ctx2], [ctx3] if ctx has been split into ctx1 and ctx2 |
688 while also diverged into ctx3. (EXPERIMENTAL)""" |
692 while also diverged into ctx3. (EXPERIMENTAL)""" |
689 repo = context.resource(mapping, 'repo') |
693 repo = context.resource(mapping, b'repo') |
690 ctx = context.resource(mapping, 'ctx') |
694 ctx = context.resource(mapping, b'ctx') |
691 if not ctx.obsolete(): |
695 if not ctx.obsolete(): |
692 return '' |
696 return b'' |
693 |
697 |
694 ssets = obsutil.successorssets(repo, ctx.node(), closest=True) |
698 ssets = obsutil.successorssets(repo, ctx.node(), closest=True) |
695 ssets = [[hex(n) for n in ss] for ss in ssets] |
699 ssets = [[hex(n) for n in ss] for ss in ssets] |
696 |
700 |
697 data = [] |
701 data = [] |
698 for ss in ssets: |
702 for ss in ssets: |
699 h = _hybrid( |
703 h = _hybrid( |
700 None, |
704 None, |
701 ss, |
705 ss, |
702 lambda x: {'ctx': repo[x]}, |
706 lambda x: {b'ctx': repo[x]}, |
703 lambda x: scmutil.formatchangeid(repo[x]), |
707 lambda x: scmutil.formatchangeid(repo[x]), |
704 ) |
708 ) |
705 data.append(h) |
709 data.append(h) |
706 |
710 |
707 # Format the successorssets |
711 # Format the successorssets |
708 def render(d): |
712 def render(d): |
709 return templateutil.stringify(context, mapping, d) |
713 return templateutil.stringify(context, mapping, d) |
710 |
714 |
711 def gen(data): |
715 def gen(data): |
712 yield "; ".join(render(d) for d in data) |
716 yield b"; ".join(render(d) for d in data) |
713 |
717 |
714 return _hybrid( |
718 return _hybrid( |
715 gen(data), data, lambda x: {'successorset': x}, pycompat.identity |
719 gen(data), data, lambda x: {b'successorset': x}, pycompat.identity |
716 ) |
720 ) |
717 |
721 |
718 |
722 |
719 @templatekeyword("succsandmarkers", requires={'repo', 'ctx'}) |
723 @templatekeyword(b"succsandmarkers", requires={b'repo', b'ctx'}) |
720 def showsuccsandmarkers(context, mapping): |
724 def showsuccsandmarkers(context, mapping): |
721 """Returns a list of dict for each final successor of ctx. The dict |
725 """Returns a list of dict for each final successor of ctx. The dict |
722 contains successors node id in "successors" keys and the list of |
726 contains successors node id in "successors" keys and the list of |
723 obs-markers from ctx to the set of successors in "markers". |
727 obs-markers from ctx to the set of successors in "markers". |
724 (EXPERIMENTAL) |
728 (EXPERIMENTAL) |
725 """ |
729 """ |
726 repo = context.resource(mapping, 'repo') |
730 repo = context.resource(mapping, b'repo') |
727 ctx = context.resource(mapping, 'ctx') |
731 ctx = context.resource(mapping, b'ctx') |
728 |
732 |
729 values = obsutil.successorsandmarkers(repo, ctx) |
733 values = obsutil.successorsandmarkers(repo, ctx) |
730 |
734 |
731 if values is None: |
735 if values is None: |
732 values = [] |
736 values = [] |
733 |
737 |
734 # Format successors and markers to avoid exposing binary to templates |
738 # Format successors and markers to avoid exposing binary to templates |
735 data = [] |
739 data = [] |
736 for i in values: |
740 for i in values: |
737 # Format successors |
741 # Format successors |
738 successors = i['successors'] |
742 successors = i[b'successors'] |
739 |
743 |
740 successors = [hex(n) for n in successors] |
744 successors = [hex(n) for n in successors] |
741 successors = _hybrid( |
745 successors = _hybrid( |
742 None, |
746 None, |
743 successors, |
747 successors, |
744 lambda x: {'ctx': repo[x]}, |
748 lambda x: {b'ctx': repo[x]}, |
745 lambda x: scmutil.formatchangeid(repo[x]), |
749 lambda x: scmutil.formatchangeid(repo[x]), |
746 ) |
750 ) |
747 |
751 |
748 # Format markers |
752 # Format markers |
749 finalmarkers = [] |
753 finalmarkers = [] |
750 for m in i['markers']: |
754 for m in i[b'markers']: |
751 hexprec = hex(m[0]) |
755 hexprec = hex(m[0]) |
752 hexsucs = tuple(hex(n) for n in m[1]) |
756 hexsucs = tuple(hex(n) for n in m[1]) |
753 hexparents = None |
757 hexparents = None |
754 if m[5] is not None: |
758 if m[5] is not None: |
755 hexparents = tuple(hex(n) for n in m[5]) |
759 hexparents = tuple(hex(n) for n in m[5]) |
756 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:] |
760 newmarker = (hexprec, hexsucs) + m[2:5] + (hexparents,) + m[6:] |
757 finalmarkers.append(newmarker) |
761 finalmarkers.append(newmarker) |
758 |
762 |
759 data.append({'successors': successors, 'markers': finalmarkers}) |
763 data.append({b'successors': successors, b'markers': finalmarkers}) |
760 |
764 |
761 return templateutil.mappinglist(data) |
765 return templateutil.mappinglist(data) |
762 |
766 |
763 |
767 |
764 @templatekeyword('p1', requires={'ctx'}) |
768 @templatekeyword(b'p1', requires={b'ctx'}) |
765 def showp1(context, mapping): |
769 def showp1(context, mapping): |
766 """Changeset. The changeset's first parent. ``{p1.rev}`` for the revision |
770 """Changeset. The changeset's first parent. ``{p1.rev}`` for the revision |
767 number, and ``{p1.node}`` for the identification hash.""" |
771 number, and ``{p1.node}`` for the identification hash.""" |
768 ctx = context.resource(mapping, 'ctx') |
772 ctx = context.resource(mapping, b'ctx') |
769 return templateutil.mappingdict({'ctx': ctx.p1()}, tmpl=_changeidtmpl) |
773 return templateutil.mappingdict({b'ctx': ctx.p1()}, tmpl=_changeidtmpl) |
770 |
774 |
771 |
775 |
772 @templatekeyword('p2', requires={'ctx'}) |
776 @templatekeyword(b'p2', requires={b'ctx'}) |
773 def showp2(context, mapping): |
777 def showp2(context, mapping): |
774 """Changeset. The changeset's second parent. ``{p2.rev}`` for the revision |
778 """Changeset. The changeset's second parent. ``{p2.rev}`` for the revision |
775 number, and ``{p2.node}`` for the identification hash.""" |
779 number, and ``{p2.node}`` for the identification hash.""" |
776 ctx = context.resource(mapping, 'ctx') |
780 ctx = context.resource(mapping, b'ctx') |
777 return templateutil.mappingdict({'ctx': ctx.p2()}, tmpl=_changeidtmpl) |
781 return templateutil.mappingdict({b'ctx': ctx.p2()}, tmpl=_changeidtmpl) |
778 |
782 |
779 |
783 |
780 @templatekeyword('p1rev', requires={'ctx'}) |
784 @templatekeyword(b'p1rev', requires={b'ctx'}) |
781 def showp1rev(context, mapping): |
785 def showp1rev(context, mapping): |
782 """Integer. The repository-local revision number of the changeset's |
786 """Integer. The repository-local revision number of the changeset's |
783 first parent, or -1 if the changeset has no parents. (DEPRECATED)""" |
787 first parent, or -1 if the changeset has no parents. (DEPRECATED)""" |
784 ctx = context.resource(mapping, 'ctx') |
788 ctx = context.resource(mapping, b'ctx') |
785 return ctx.p1().rev() |
789 return ctx.p1().rev() |
786 |
790 |
787 |
791 |
788 @templatekeyword('p2rev', requires={'ctx'}) |
792 @templatekeyword(b'p2rev', requires={b'ctx'}) |
789 def showp2rev(context, mapping): |
793 def showp2rev(context, mapping): |
790 """Integer. The repository-local revision number of the changeset's |
794 """Integer. The repository-local revision number of the changeset's |
791 second parent, or -1 if the changeset has no second parent. (DEPRECATED)""" |
795 second parent, or -1 if the changeset has no second parent. (DEPRECATED)""" |
792 ctx = context.resource(mapping, 'ctx') |
796 ctx = context.resource(mapping, b'ctx') |
793 return ctx.p2().rev() |
797 return ctx.p2().rev() |
794 |
798 |
795 |
799 |
796 @templatekeyword('p1node', requires={'ctx'}) |
800 @templatekeyword(b'p1node', requires={b'ctx'}) |
797 def showp1node(context, mapping): |
801 def showp1node(context, mapping): |
798 """String. The identification hash of the changeset's first parent, |
802 """String. The identification hash of the changeset's first parent, |
799 as a 40 digit hexadecimal string. If the changeset has no parents, all |
803 as a 40 digit hexadecimal string. If the changeset has no parents, all |
800 digits are 0. (DEPRECATED)""" |
804 digits are 0. (DEPRECATED)""" |
801 ctx = context.resource(mapping, 'ctx') |
805 ctx = context.resource(mapping, b'ctx') |
802 return ctx.p1().hex() |
806 return ctx.p1().hex() |
803 |
807 |
804 |
808 |
805 @templatekeyword('p2node', requires={'ctx'}) |
809 @templatekeyword(b'p2node', requires={b'ctx'}) |
806 def showp2node(context, mapping): |
810 def showp2node(context, mapping): |
807 """String. The identification hash of the changeset's second |
811 """String. The identification hash of the changeset's second |
808 parent, as a 40 digit hexadecimal string. If the changeset has no second |
812 parent, as a 40 digit hexadecimal string. If the changeset has no second |
809 parent, all digits are 0. (DEPRECATED)""" |
813 parent, all digits are 0. (DEPRECATED)""" |
810 ctx = context.resource(mapping, 'ctx') |
814 ctx = context.resource(mapping, b'ctx') |
811 return ctx.p2().hex() |
815 return ctx.p2().hex() |
812 |
816 |
813 |
817 |
814 @templatekeyword('parents', requires={'repo', 'ctx'}) |
818 @templatekeyword(b'parents', requires={b'repo', b'ctx'}) |
815 def showparents(context, mapping): |
819 def showparents(context, mapping): |
816 """List of strings. The parents of the changeset in "rev:node" |
820 """List of strings. The parents of the changeset in "rev:node" |
817 format. If the changeset has only one "natural" parent (the predecessor |
821 format. If the changeset has only one "natural" parent (the predecessor |
818 revision) nothing is shown.""" |
822 revision) nothing is shown.""" |
819 repo = context.resource(mapping, 'repo') |
823 repo = context.resource(mapping, b'repo') |
820 ctx = context.resource(mapping, 'ctx') |
824 ctx = context.resource(mapping, b'ctx') |
821 pctxs = scmutil.meaningfulparents(repo, ctx) |
825 pctxs = scmutil.meaningfulparents(repo, ctx) |
822 prevs = [p.rev() for p in pctxs] |
826 prevs = [p.rev() for p in pctxs] |
823 parents = [ |
827 parents = [ |
824 [('rev', p.rev()), ('node', p.hex()), ('phase', p.phasestr())] |
828 [(b'rev', p.rev()), (b'node', p.hex()), (b'phase', p.phasestr())] |
825 for p in pctxs |
829 for p in pctxs |
826 ] |
830 ] |
827 f = _showcompatlist(context, mapping, 'parent', parents) |
831 f = _showcompatlist(context, mapping, b'parent', parents) |
828 return _hybrid( |
832 return _hybrid( |
829 f, |
833 f, |
830 prevs, |
834 prevs, |
831 lambda x: {'ctx': repo[x]}, |
835 lambda x: {b'ctx': repo[x]}, |
832 lambda x: scmutil.formatchangeid(repo[x]), |
836 lambda x: scmutil.formatchangeid(repo[x]), |
833 keytype=int, |
837 keytype=int, |
834 ) |
838 ) |
835 |
839 |
836 |
840 |
837 @templatekeyword('phase', requires={'ctx'}) |
841 @templatekeyword(b'phase', requires={b'ctx'}) |
838 def showphase(context, mapping): |
842 def showphase(context, mapping): |
839 """String. The changeset phase name.""" |
843 """String. The changeset phase name.""" |
840 ctx = context.resource(mapping, 'ctx') |
844 ctx = context.resource(mapping, b'ctx') |
841 return ctx.phasestr() |
845 return ctx.phasestr() |
842 |
846 |
843 |
847 |
844 @templatekeyword('phaseidx', requires={'ctx'}) |
848 @templatekeyword(b'phaseidx', requires={b'ctx'}) |
845 def showphaseidx(context, mapping): |
849 def showphaseidx(context, mapping): |
846 """Integer. The changeset phase index. (ADVANCED)""" |
850 """Integer. The changeset phase index. (ADVANCED)""" |
847 ctx = context.resource(mapping, 'ctx') |
851 ctx = context.resource(mapping, b'ctx') |
848 return ctx.phase() |
852 return ctx.phase() |
849 |
853 |
850 |
854 |
851 @templatekeyword('rev', requires={'ctx'}) |
855 @templatekeyword(b'rev', requires={b'ctx'}) |
852 def showrev(context, mapping): |
856 def showrev(context, mapping): |
853 """Integer. The repository-local changeset revision number.""" |
857 """Integer. The repository-local changeset revision number.""" |
854 ctx = context.resource(mapping, 'ctx') |
858 ctx = context.resource(mapping, b'ctx') |
855 return scmutil.intrev(ctx) |
859 return scmutil.intrev(ctx) |
856 |
860 |
857 |
861 |
858 def showrevslist(context, mapping, name, revs): |
862 def showrevslist(context, mapping, name, revs): |
859 """helper to generate a list of revisions in which a mapped template will |
863 """helper to generate a list of revisions in which a mapped template will |
860 be evaluated""" |
864 be evaluated""" |
861 repo = context.resource(mapping, 'repo') |
865 repo = context.resource(mapping, b'repo') |
862 # revs may be a smartset; don't compute it until f() has to be evaluated |
866 # revs may be a smartset; don't compute it until f() has to be evaluated |
863 def f(): |
867 def f(): |
864 srevs = ['%d' % r for r in revs] |
868 srevs = [b'%d' % r for r in revs] |
865 return _showcompatlist(context, mapping, name, srevs) |
869 return _showcompatlist(context, mapping, name, srevs) |
866 |
870 |
867 return _hybrid( |
871 return _hybrid( |
868 f, |
872 f, |
869 revs, |
873 revs, |
870 lambda x: {name: x, 'ctx': repo[x]}, |
874 lambda x: {name: x, b'ctx': repo[x]}, |
871 pycompat.identity, |
875 pycompat.identity, |
872 keytype=int, |
876 keytype=int, |
873 ) |
877 ) |
874 |
878 |
875 |
879 |
876 @templatekeyword('subrepos', requires={'ctx'}) |
880 @templatekeyword(b'subrepos', requires={b'ctx'}) |
877 def showsubrepos(context, mapping): |
881 def showsubrepos(context, mapping): |
878 """List of strings. Updated subrepositories in the changeset.""" |
882 """List of strings. Updated subrepositories in the changeset.""" |
879 ctx = context.resource(mapping, 'ctx') |
883 ctx = context.resource(mapping, b'ctx') |
880 substate = ctx.substate |
884 substate = ctx.substate |
881 if not substate: |
885 if not substate: |
882 return compatlist(context, mapping, 'subrepo', []) |
886 return compatlist(context, mapping, b'subrepo', []) |
883 psubstate = ctx.p1().substate or {} |
887 psubstate = ctx.p1().substate or {} |
884 subrepos = [] |
888 subrepos = [] |
885 for sub in substate: |
889 for sub in substate: |
886 if sub not in psubstate or substate[sub] != psubstate[sub]: |
890 if sub not in psubstate or substate[sub] != psubstate[sub]: |
887 subrepos.append(sub) # modified or newly added in ctx |
891 subrepos.append(sub) # modified or newly added in ctx |
888 for sub in psubstate: |
892 for sub in psubstate: |
889 if sub not in substate: |
893 if sub not in substate: |
890 subrepos.append(sub) # removed in ctx |
894 subrepos.append(sub) # removed in ctx |
891 return compatlist(context, mapping, 'subrepo', sorted(subrepos)) |
895 return compatlist(context, mapping, b'subrepo', sorted(subrepos)) |
892 |
896 |
893 |
897 |
894 # don't remove "showtags" definition, even though namespaces will put |
898 # don't remove "showtags" definition, even though namespaces will put |
895 # a helper function for "tags" keyword into "keywords" map automatically, |
899 # a helper function for "tags" keyword into "keywords" map automatically, |
896 # because online help text is built without namespaces initialization |
900 # because online help text is built without namespaces initialization |
897 @templatekeyword('tags', requires={'repo', 'ctx'}) |
901 @templatekeyword(b'tags', requires={b'repo', b'ctx'}) |
898 def showtags(context, mapping): |
902 def showtags(context, mapping): |
899 """List of strings. Any tags associated with the changeset.""" |
903 """List of strings. Any tags associated with the changeset.""" |
900 return shownames(context, mapping, 'tags') |
904 return shownames(context, mapping, b'tags') |
901 |
905 |
902 |
906 |
903 @templatekeyword('termwidth', requires={'ui'}) |
907 @templatekeyword(b'termwidth', requires={b'ui'}) |
904 def showtermwidth(context, mapping): |
908 def showtermwidth(context, mapping): |
905 """Integer. The width of the current terminal.""" |
909 """Integer. The width of the current terminal.""" |
906 ui = context.resource(mapping, 'ui') |
910 ui = context.resource(mapping, b'ui') |
907 return ui.termwidth() |
911 return ui.termwidth() |
908 |
912 |
909 |
913 |
910 @templatekeyword('user', requires={'ctx'}) |
914 @templatekeyword(b'user', requires={b'ctx'}) |
911 def showuser(context, mapping): |
915 def showuser(context, mapping): |
912 """String. The unmodified author of the changeset.""" |
916 """String. The unmodified author of the changeset.""" |
913 ctx = context.resource(mapping, 'ctx') |
917 ctx = context.resource(mapping, b'ctx') |
914 return ctx.user() |
918 return ctx.user() |
915 |
919 |
916 |
920 |
917 @templatekeyword('instabilities', requires={'ctx'}) |
921 @templatekeyword(b'instabilities', requires={b'ctx'}) |
918 def showinstabilities(context, mapping): |
922 def showinstabilities(context, mapping): |
919 """List of strings. Evolution instabilities affecting the changeset. |
923 """List of strings. Evolution instabilities affecting the changeset. |
920 (EXPERIMENTAL) |
924 (EXPERIMENTAL) |
921 """ |
925 """ |
922 ctx = context.resource(mapping, 'ctx') |
926 ctx = context.resource(mapping, b'ctx') |
923 return compatlist( |
927 return compatlist( |
924 context, |
928 context, |
925 mapping, |
929 mapping, |
926 'instability', |
930 b'instability', |
927 ctx.instabilities(), |
931 ctx.instabilities(), |
928 plural='instabilities', |
932 plural=b'instabilities', |
929 ) |
933 ) |
930 |
934 |
931 |
935 |
932 @templatekeyword('verbosity', requires={'ui'}) |
936 @templatekeyword(b'verbosity', requires={b'ui'}) |
933 def showverbosity(context, mapping): |
937 def showverbosity(context, mapping): |
934 """String. The current output verbosity in 'debug', 'quiet', 'verbose', |
938 """String. The current output verbosity in 'debug', 'quiet', 'verbose', |
935 or ''.""" |
939 or ''.""" |
936 ui = context.resource(mapping, 'ui') |
940 ui = context.resource(mapping, b'ui') |
937 # see logcmdutil.changesettemplater for priority of these flags |
941 # see logcmdutil.changesettemplater for priority of these flags |
938 if ui.debugflag: |
942 if ui.debugflag: |
939 return 'debug' |
943 return b'debug' |
940 elif ui.quiet: |
944 elif ui.quiet: |
941 return 'quiet' |
945 return b'quiet' |
942 elif ui.verbose: |
946 elif ui.verbose: |
943 return 'verbose' |
947 return b'verbose' |
944 return '' |
948 return b'' |
945 |
949 |
946 |
950 |
947 @templatekeyword('whyunstable', requires={'repo', 'ctx'}) |
951 @templatekeyword(b'whyunstable', requires={b'repo', b'ctx'}) |
948 def showwhyunstable(context, mapping): |
952 def showwhyunstable(context, mapping): |
949 """List of dicts explaining all instabilities of a changeset. |
953 """List of dicts explaining all instabilities of a changeset. |
950 (EXPERIMENTAL) |
954 (EXPERIMENTAL) |
951 """ |
955 """ |
952 repo = context.resource(mapping, 'repo') |
956 repo = context.resource(mapping, b'repo') |
953 ctx = context.resource(mapping, 'ctx') |
957 ctx = context.resource(mapping, b'ctx') |
954 |
958 |
955 def formatnode(ctx): |
959 def formatnode(ctx): |
956 return '%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr()) |
960 return b'%s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr()) |
957 |
961 |
958 entries = obsutil.whyunstable(repo, ctx) |
962 entries = obsutil.whyunstable(repo, ctx) |
959 |
963 |
960 for entry in entries: |
964 for entry in entries: |
961 if entry.get('divergentnodes'): |
965 if entry.get(b'divergentnodes'): |
962 dnodes = entry['divergentnodes'] |
966 dnodes = entry[b'divergentnodes'] |
963 dnhybrid = _hybrid( |
967 dnhybrid = _hybrid( |
964 None, |
968 None, |
965 [dnode.hex() for dnode in dnodes], |
969 [dnode.hex() for dnode in dnodes], |
966 lambda x: {'ctx': repo[x]}, |
970 lambda x: {b'ctx': repo[x]}, |
967 lambda x: formatnode(repo[x]), |
971 lambda x: formatnode(repo[x]), |
968 ) |
972 ) |
969 entry['divergentnodes'] = dnhybrid |
973 entry[b'divergentnodes'] = dnhybrid |
970 |
974 |
971 tmpl = ( |
975 tmpl = ( |
972 '{instability}:{if(divergentnodes, " ")}{divergentnodes} ' |
976 b'{instability}:{if(divergentnodes, " ")}{divergentnodes} ' |
973 '{reason} {node|short}' |
977 b'{reason} {node|short}' |
974 ) |
978 ) |
975 return templateutil.mappinglist(entries, tmpl=tmpl, sep='\n') |
979 return templateutil.mappinglist(entries, tmpl=tmpl, sep=b'\n') |
976 |
980 |
977 |
981 |
978 def loadkeyword(ui, extname, registrarobj): |
982 def loadkeyword(ui, extname, registrarobj): |
979 """Load template keyword from specified registrarobj |
983 """Load template keyword from specified registrarobj |
980 """ |
984 """ |