245 ('f', 'file', None, _('list the filename')), |
245 ('f', 'file', None, _('list the filename')), |
246 ('d', 'date', None, _('list the date (short with -q)')), |
246 ('d', 'date', None, _('list the date (short with -q)')), |
247 ('n', 'number', None, _('list the revision number (default)')), |
247 ('n', 'number', None, _('list the revision number (default)')), |
248 ('c', 'changeset', None, _('list the changeset')), |
248 ('c', 'changeset', None, _('list the changeset')), |
249 ('l', 'line-number', None, _('show line number at the first appearance')) |
249 ('l', 'line-number', None, _('show line number at the first appearance')) |
250 ] + diffwsopts + walkopts, |
250 ] + diffwsopts + walkopts + formatteropts, |
251 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'), |
251 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'), |
252 inferrepo=True) |
252 inferrepo=True) |
253 def annotate(ui, repo, *pats, **opts): |
253 def annotate(ui, repo, *pats, **opts): |
254 """show changeset information by line for each file |
254 """show changeset information by line for each file |
255 |
255 |
272 if opts.get('follow'): |
272 if opts.get('follow'): |
273 # --follow is deprecated and now just an alias for -f/--file |
273 # --follow is deprecated and now just an alias for -f/--file |
274 # to mimic the behavior of Mercurial before version 1.5 |
274 # to mimic the behavior of Mercurial before version 1.5 |
275 opts['file'] = True |
275 opts['file'] = True |
276 |
276 |
|
277 fm = ui.formatter('annotate', opts) |
277 datefunc = ui.quiet and util.shortdate or util.datestr |
278 datefunc = ui.quiet and util.shortdate or util.datestr |
278 hexfn = ui.debugflag and hex or short |
279 if fm or ui.debugflag: |
|
280 hexfn = hex |
|
281 else: |
|
282 hexfn = short |
279 |
283 |
280 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser), |
284 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser), |
281 ('number', ' ', lambda x: x[0].rev(), str), |
285 ('number', ' ', lambda x: x[0].rev(), str), |
282 ('changeset', ' ', lambda x: hexfn(x[0].node()), str), |
286 ('changeset', ' ', lambda x: hexfn(x[0].node()), str), |
283 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)), |
287 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)), |
284 ('file', ' ', lambda x: x[0].path(), str), |
288 ('file', ' ', lambda x: x[0].path(), str), |
285 ('line_number', ':', lambda x: x[1], str), |
289 ('line_number', ':', lambda x: x[1], str), |
286 ] |
290 ] |
|
291 fieldnamemap = {'number': 'rev', 'changeset': 'node'} |
287 |
292 |
288 if (not opts.get('user') and not opts.get('changeset') |
293 if (not opts.get('user') and not opts.get('changeset') |
289 and not opts.get('date') and not opts.get('file')): |
294 and not opts.get('date') and not opts.get('file')): |
290 opts['number'] = True |
295 opts['number'] = True |
291 |
296 |
292 linenumber = opts.get('line_number') is not None |
297 linenumber = opts.get('line_number') is not None |
293 if linenumber and (not opts.get('changeset')) and (not opts.get('number')): |
298 if linenumber and (not opts.get('changeset')) and (not opts.get('number')): |
294 raise util.Abort(_('at least one of -n/-c is required for -l')) |
299 raise util.Abort(_('at least one of -n/-c is required for -l')) |
295 |
300 |
296 def makefunc(get, fmt): |
301 if fm: |
297 return lambda x: fmt(get(x)) |
302 def makefunc(get, fmt): |
|
303 return get |
|
304 else: |
|
305 def makefunc(get, fmt): |
|
306 return lambda x: fmt(get(x)) |
298 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap |
307 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap |
299 if opts.get(op)] |
308 if opts.get(op)] |
300 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column |
309 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column |
|
310 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap |
|
311 if opts.get(op)) |
301 |
312 |
302 def bad(x, y): |
313 def bad(x, y): |
303 raise util.Abort("%s: %s" % (x, y)) |
314 raise util.Abort("%s: %s" % (x, y)) |
304 |
315 |
305 ctx = scmutil.revsingle(repo, opts.get('rev')) |
316 ctx = scmutil.revsingle(repo, opts.get('rev')) |
308 follow = not opts.get('no_follow') |
319 follow = not opts.get('no_follow') |
309 diffopts = patch.diffopts(ui, opts, section='annotate') |
320 diffopts = patch.diffopts(ui, opts, section='annotate') |
310 for abs in ctx.walk(m): |
321 for abs in ctx.walk(m): |
311 fctx = ctx[abs] |
322 fctx = ctx[abs] |
312 if not opts.get('text') and util.binary(fctx.data()): |
323 if not opts.get('text') and util.binary(fctx.data()): |
313 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs)) |
324 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs)) |
314 continue |
325 continue |
315 |
326 |
316 lines = fctx.annotate(follow=follow, linenumber=linenumber, |
327 lines = fctx.annotate(follow=follow, linenumber=linenumber, |
317 diffopts=diffopts) |
328 diffopts=diffopts) |
318 formats = [] |
329 formats = [] |
319 pieces = [] |
330 pieces = [] |
320 |
331 |
321 for f, sep in funcmap: |
332 for f, sep in funcmap: |
322 l = [f(n) for n, dummy in lines] |
333 l = [f(n) for n, dummy in lines] |
323 if l: |
334 if l: |
324 sizes = [encoding.colwidth(x) for x in l] |
335 if fm: |
325 ml = max(sizes) |
336 formats.append(['%s' for x in l]) |
326 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes]) |
337 else: |
|
338 sizes = [encoding.colwidth(x) for x in l] |
|
339 ml = max(sizes) |
|
340 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes]) |
327 pieces.append(l) |
341 pieces.append(l) |
328 |
342 |
329 for f, p, l in zip(zip(*formats), zip(*pieces), lines): |
343 for f, p, l in zip(zip(*formats), zip(*pieces), lines): |
330 ui.write("".join(f) % p) |
344 fm.startitem() |
331 ui.write(": %s" % l[1]) |
345 fm.write(fields, "".join(f), *p) |
|
346 fm.write('line', ": %s", l[1]) |
332 |
347 |
333 if lines and not lines[-1][1].endswith('\n'): |
348 if lines and not lines[-1][1].endswith('\n'): |
334 ui.write('\n') |
349 fm.plain('\n') |
|
350 |
|
351 fm.end() |
335 |
352 |
336 @command('archive', |
353 @command('archive', |
337 [('', 'no-decode', None, _('do not pass files through decoders')), |
354 [('', 'no-decode', None, _('do not pass files through decoders')), |
338 ('p', 'prefix', '', _('directory prefix for files in archive'), |
355 ('p', 'prefix', '', _('directory prefix for files in archive'), |
339 _('PREFIX')), |
356 _('PREFIX')), |