formatter.py
178 lines
| 5.8 KiB
| text/x-python
|
PythonLexer
Augie Fackler
|
r39243 | # Copyright 2016-present Facebook. All Rights Reserved. | ||
# | ||||
# format: defines the format used to output annotate result | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
Matt Harbison
|
r52756 | from __future__ import annotations | ||
Augie Fackler
|
r39243 | |||
Joerg Sonnenberger
|
r46729 | from mercurial.node import ( | ||
hex, | ||||
short, | ||||
) | ||||
Augie Fackler
|
r39243 | from mercurial import ( | ||
encoding, | ||||
pycompat, | ||||
templatefilters, | ||||
util, | ||||
) | ||||
Augie Fackler
|
r43346 | from mercurial.utils import dateutil | ||
Augie Fackler
|
r39243 | |||
Raphaël Gomès
|
r52596 | |||
Augie Fackler
|
r39243 | # imitating mercurial.commands.annotate, not using the vanilla formatter since | ||
# the data structures are a bit different, and we have some fast paths. | ||||
Gregory Szorc
|
r49801 | class defaultformatter: | ||
Augie Fackler
|
r39243 | """the default formatter that does leftpad and support some common flags""" | ||
def __init__(self, ui, repo, opts): | ||||
self.ui = ui | ||||
self.opts = opts | ||||
if ui.quiet: | ||||
datefunc = dateutil.shortdate | ||||
else: | ||||
datefunc = dateutil.datestr | ||||
datefunc = util.cachefunc(datefunc) | ||||
getctx = util.cachefunc(lambda x: repo[x[0]]) | ||||
hexfunc = self._hexfunc | ||||
# special handling working copy "changeset" and "rev" functions | ||||
Augie Fackler
|
r43347 | if self.opts.get(b'rev') == b'wdir()': | ||
Augie Fackler
|
r39243 | orig = hexfunc | ||
hexfunc = lambda x: None if x is None else orig(x) | ||||
Augie Fackler
|
r43347 | wnode = hexfunc(repo[b'.'].node()) + b'+' | ||
wrev = b'%d' % repo[b'.'].rev() | ||||
wrevpad = b'' | ||||
if not opts.get(b'changeset'): # only show + if changeset is hidden | ||||
wrev += b'+' | ||||
wrevpad = b' ' | ||||
revenc = lambda x: wrev if x is None else (b'%d' % x) + wrevpad | ||||
Augie Fackler
|
r43346 | |||
Pulkit Goyal
|
r40763 | def csetenc(x): | ||
if x is None: | ||||
return wnode | ||||
Augie Fackler
|
r43347 | return pycompat.bytestr(x) + b' ' | ||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r39243 | else: | ||
Pulkit Goyal
|
r40763 | revenc = csetenc = pycompat.bytestr | ||
Augie Fackler
|
r39243 | |||
# opt name, separator, raw value (for json/plain), encoder (for plain) | ||||
Augie Fackler
|
r43346 | opmap = [ | ||
Augie Fackler
|
r43347 | (b'user', b' ', lambda x: getctx(x).user(), ui.shortuser), | ||
(b'number', b' ', lambda x: getctx(x).rev(), revenc), | ||||
(b'changeset', b' ', lambda x: hexfunc(x[0]), csetenc), | ||||
(b'date', b' ', lambda x: getctx(x).date(), datefunc), | ||||
(b'file', b' ', lambda x: x[2], pycompat.bytestr), | ||||
(b'line_number', b':', lambda x: x[1] + 1, pycompat.bytestr), | ||||
Augie Fackler
|
r43346 | ] | ||
Augie Fackler
|
r43347 | fieldnamemap = {b'number': b'rev', b'changeset': b'node'} | ||
Augie Fackler
|
r43346 | funcmap = [ | ||
(get, sep, fieldnamemap.get(op, op), enc) | ||||
for op, sep, get, enc in opmap | ||||
if opts.get(op) | ||||
] | ||||
Augie Fackler
|
r39243 | # no separator for first column | ||
funcmap[0] = list(funcmap[0]) | ||||
Augie Fackler
|
r43347 | funcmap[0][1] = b'' | ||
Augie Fackler
|
r39243 | self.funcmap = funcmap | ||
def write(self, annotatedresult, lines=None, existinglines=None): | ||||
"""(annotateresult, [str], set([rev, linenum])) -> None. write output. | ||||
annotateresult can be [(node, linenum, path)], or [(node, linenum)] | ||||
""" | ||||
Augie Fackler
|
r43346 | pieces = [] # [[str]] | ||
maxwidths = [] # [int] | ||||
Augie Fackler
|
r39243 | |||
# calculate padding | ||||
for f, sep, name, enc in self.funcmap: | ||||
l = [enc(f(x)) for x in annotatedresult] | ||||
pieces.append(l) | ||||
Augie Fackler
|
r43347 | if name in [b'node', b'date']: # node and date has fixed size | ||
Augie Fackler
|
r39243 | l = l[:1] | ||
Pulkit Goyal
|
r39762 | widths = pycompat.maplist(encoding.colwidth, set(l)) | ||
Augie Fackler
|
r43346 | maxwidth = max(widths) if widths else 0 | ||
Augie Fackler
|
r39243 | maxwidths.append(maxwidth) | ||
# buffered output | ||||
Augie Fackler
|
r43347 | result = b'' | ||
Manuel Jacob
|
r50179 | for i in range(len(annotatedresult)): | ||
Augie Fackler
|
r39243 | for j, p in enumerate(pieces): | ||
sep = self.funcmap[j][1] | ||||
Augie Fackler
|
r43347 | padding = b' ' * (maxwidths[j] - len(p[i])) | ||
Augie Fackler
|
r39243 | result += sep + padding + p[i] | ||
if lines: | ||||
if existinglines is None: | ||||
Augie Fackler
|
r43347 | result += b': ' + lines[i] | ||
Augie Fackler
|
r43346 | else: # extra formatting showing whether a line exists | ||
Augie Fackler
|
r39243 | key = (annotatedresult[i][0], annotatedresult[i][1]) | ||
if key in existinglines: | ||||
Augie Fackler
|
r43347 | result += b': ' + lines[i] | ||
Augie Fackler
|
r39243 | else: | ||
Augie Fackler
|
r43347 | result += b': ' + self.ui.label( | ||
b'-' + lines[i], b'diff.deleted' | ||||
Augie Fackler
|
r43346 | ) | ||
Augie Fackler
|
r39243 | |||
Augie Fackler
|
r43347 | if result[-1:] != b'\n': | ||
result += b'\n' | ||||
Augie Fackler
|
r39243 | |||
self.ui.write(result) | ||||
@util.propertycache | ||||
def _hexfunc(self): | ||||
Augie Fackler
|
r43347 | if self.ui.debugflag or self.opts.get(b'long_hash'): | ||
Joerg Sonnenberger
|
r46729 | return hex | ||
Augie Fackler
|
r39243 | else: | ||
Joerg Sonnenberger
|
r46729 | return short | ||
Augie Fackler
|
r39243 | |||
def end(self): | ||||
pass | ||||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r39243 | class jsonformatter(defaultformatter): | ||
def __init__(self, ui, repo, opts): | ||||
super(jsonformatter, self).__init__(ui, repo, opts) | ||||
Augie Fackler
|
r43347 | self.ui.write(b'[') | ||
Augie Fackler
|
r39243 | self.needcomma = False | ||
def write(self, annotatedresult, lines=None, existinglines=None): | ||||
if annotatedresult: | ||||
self._writecomma() | ||||
Augie Fackler
|
r43346 | pieces = [ | ||
(name, pycompat.maplist(f, annotatedresult)) | ||||
for f, sep, name, enc in self.funcmap | ||||
] | ||||
Augie Fackler
|
r39243 | if lines is not None: | ||
Augie Fackler
|
r43347 | pieces.append((b'line', lines)) | ||
Augie Fackler
|
r39243 | pieces.sort() | ||
Augie Fackler
|
r43347 | seps = [b','] * len(pieces[:-1]) + [b''] | ||
Augie Fackler
|
r39243 | |||
Augie Fackler
|
r43347 | result = b'' | ||
Augie Fackler
|
r39243 | lasti = len(annotatedresult) - 1 | ||
Manuel Jacob
|
r50179 | for i in range(len(annotatedresult)): | ||
Augie Fackler
|
r43347 | result += b'\n {\n' | ||
Augie Fackler
|
r39243 | for j, p in enumerate(pieces): | ||
k, vs = p | ||||
Augie Fackler
|
r43347 | result += b' "%s": %s%s\n' % ( | ||
Augie Fackler
|
r43346 | k, | ||
templatefilters.json(vs[i], paranoid=False), | ||||
seps[j], | ||||
) | ||||
Augie Fackler
|
r43347 | result += b' }%s' % (b'' if i == lasti else b',') | ||
Augie Fackler
|
r39243 | if lasti >= 0: | ||
self.needcomma = True | ||||
self.ui.write(result) | ||||
def _writecomma(self): | ||||
if self.needcomma: | ||||
Augie Fackler
|
r43347 | self.ui.write(b',') | ||
Augie Fackler
|
r39243 | self.needcomma = False | ||
@util.propertycache | ||||
def _hexfunc(self): | ||||
Joerg Sonnenberger
|
r46729 | return hex | ||
Augie Fackler
|
r39243 | |||
def end(self): | ||||
Augie Fackler
|
r43347 | self.ui.write(b'\n]\n') | ||