hgext/fastannotate/formatter.py
changeset 43076 2372284d9457
parent 41398 2ff8994ac71d
child 43077 687b865b95ad
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
    11     node,
    11     node,
    12     pycompat,
    12     pycompat,
    13     templatefilters,
    13     templatefilters,
    14     util,
    14     util,
    15 )
    15 )
    16 from mercurial.utils import (
    16 from mercurial.utils import dateutil
    17         dateutil,
       
    18 )
       
    19 
    17 
    20 # imitating mercurial.commands.annotate, not using the vanilla formatter since
    18 # imitating mercurial.commands.annotate, not using the vanilla formatter since
    21 # the data structures are a bit different, and we have some fast paths.
    19 # the data structures are a bit different, and we have some fast paths.
    22 class defaultformatter(object):
    20 class defaultformatter(object):
    23     """the default formatter that does leftpad and support some common flags"""
    21     """the default formatter that does leftpad and support some common flags"""
    39             orig = hexfunc
    37             orig = hexfunc
    40             hexfunc = lambda x: None if x is None else orig(x)
    38             hexfunc = lambda x: None if x is None else orig(x)
    41             wnode = hexfunc(repo['.'].node()) + '+'
    39             wnode = hexfunc(repo['.'].node()) + '+'
    42             wrev = '%d' % repo['.'].rev()
    40             wrev = '%d' % repo['.'].rev()
    43             wrevpad = ''
    41             wrevpad = ''
    44             if not opts.get('changeset'): # only show + if changeset is hidden
    42             if not opts.get('changeset'):  # only show + if changeset is hidden
    45                 wrev += '+'
    43                 wrev += '+'
    46                 wrevpad = ' '
    44                 wrevpad = ' '
    47             revenc = lambda x: wrev if x is None else ('%d' % x) + wrevpad
    45             revenc = lambda x: wrev if x is None else ('%d' % x) + wrevpad
       
    46 
    48             def csetenc(x):
    47             def csetenc(x):
    49                 if x is None:
    48                 if x is None:
    50                     return wnode
    49                     return wnode
    51                 return pycompat.bytestr(x) + ' '
    50                 return pycompat.bytestr(x) + ' '
       
    51 
    52         else:
    52         else:
    53             revenc = csetenc = pycompat.bytestr
    53             revenc = csetenc = pycompat.bytestr
    54 
    54 
    55         # opt name, separator, raw value (for json/plain), encoder (for plain)
    55         # opt name, separator, raw value (for json/plain), encoder (for plain)
    56         opmap = [('user', ' ', lambda x: getctx(x).user(), ui.shortuser),
    56         opmap = [
    57                  ('number', ' ', lambda x: getctx(x).rev(), revenc),
    57             ('user', ' ', lambda x: getctx(x).user(), ui.shortuser),
    58                  ('changeset', ' ', lambda x: hexfunc(x[0]), csetenc),
    58             ('number', ' ', lambda x: getctx(x).rev(), revenc),
    59                  ('date', ' ', lambda x: getctx(x).date(), datefunc),
    59             ('changeset', ' ', lambda x: hexfunc(x[0]), csetenc),
    60                  ('file', ' ', lambda x: x[2], pycompat.bytestr),
    60             ('date', ' ', lambda x: getctx(x).date(), datefunc),
    61                  ('line_number', ':', lambda x: x[1] + 1, pycompat.bytestr)]
    61             ('file', ' ', lambda x: x[2], pycompat.bytestr),
       
    62             ('line_number', ':', lambda x: x[1] + 1, pycompat.bytestr),
       
    63         ]
    62         fieldnamemap = {'number': 'rev', 'changeset': 'node'}
    64         fieldnamemap = {'number': 'rev', 'changeset': 'node'}
    63         funcmap = [(get, sep, fieldnamemap.get(op, op), enc)
    65         funcmap = [
    64                    for op, sep, get, enc in opmap
    66             (get, sep, fieldnamemap.get(op, op), enc)
    65                    if opts.get(op)]
    67             for op, sep, get, enc in opmap
       
    68             if opts.get(op)
       
    69         ]
    66         # no separator for first column
    70         # no separator for first column
    67         funcmap[0] = list(funcmap[0])
    71         funcmap[0] = list(funcmap[0])
    68         funcmap[0][1] = ''
    72         funcmap[0][1] = ''
    69         self.funcmap = funcmap
    73         self.funcmap = funcmap
    70 
    74 
    71     def write(self, annotatedresult, lines=None, existinglines=None):
    75     def write(self, annotatedresult, lines=None, existinglines=None):
    72         """(annotateresult, [str], set([rev, linenum])) -> None. write output.
    76         """(annotateresult, [str], set([rev, linenum])) -> None. write output.
    73         annotateresult can be [(node, linenum, path)], or [(node, linenum)]
    77         annotateresult can be [(node, linenum, path)], or [(node, linenum)]
    74         """
    78         """
    75         pieces = [] # [[str]]
    79         pieces = []  # [[str]]
    76         maxwidths = [] # [int]
    80         maxwidths = []  # [int]
    77 
    81 
    78         # calculate padding
    82         # calculate padding
    79         for f, sep, name, enc in self.funcmap:
    83         for f, sep, name, enc in self.funcmap:
    80             l = [enc(f(x)) for x in annotatedresult]
    84             l = [enc(f(x)) for x in annotatedresult]
    81             pieces.append(l)
    85             pieces.append(l)
    82             if name in ['node', 'date']: # node and date has fixed size
    86             if name in ['node', 'date']:  # node and date has fixed size
    83                 l = l[:1]
    87                 l = l[:1]
    84             widths = pycompat.maplist(encoding.colwidth, set(l))
    88             widths = pycompat.maplist(encoding.colwidth, set(l))
    85             maxwidth = (max(widths) if widths else 0)
    89             maxwidth = max(widths) if widths else 0
    86             maxwidths.append(maxwidth)
    90             maxwidths.append(maxwidth)
    87 
    91 
    88         # buffered output
    92         # buffered output
    89         result = ''
    93         result = ''
    90         for i in pycompat.xrange(len(annotatedresult)):
    94         for i in pycompat.xrange(len(annotatedresult)):
    93                 padding = ' ' * (maxwidths[j] - len(p[i]))
    97                 padding = ' ' * (maxwidths[j] - len(p[i]))
    94                 result += sep + padding + p[i]
    98                 result += sep + padding + p[i]
    95             if lines:
    99             if lines:
    96                 if existinglines is None:
   100                 if existinglines is None:
    97                     result += ': ' + lines[i]
   101                     result += ': ' + lines[i]
    98                 else: # extra formatting showing whether a line exists
   102                 else:  # extra formatting showing whether a line exists
    99                     key = (annotatedresult[i][0], annotatedresult[i][1])
   103                     key = (annotatedresult[i][0], annotatedresult[i][1])
   100                     if key in existinglines:
   104                     if key in existinglines:
   101                         result += ':  ' + lines[i]
   105                         result += ':  ' + lines[i]
   102                     else:
   106                     else:
   103                         result += ': ' + self.ui.label('-' + lines[i],
   107                         result += ': ' + self.ui.label(
   104                                                        'diff.deleted')
   108                             '-' + lines[i], 'diff.deleted'
       
   109                         )
   105 
   110 
   106             if result[-1:] != '\n':
   111             if result[-1:] != '\n':
   107                 result += '\n'
   112                 result += '\n'
   108 
   113 
   109         self.ui.write(result)
   114         self.ui.write(result)
   116             return node.short
   121             return node.short
   117 
   122 
   118     def end(self):
   123     def end(self):
   119         pass
   124         pass
   120 
   125 
       
   126 
   121 class jsonformatter(defaultformatter):
   127 class jsonformatter(defaultformatter):
   122     def __init__(self, ui, repo, opts):
   128     def __init__(self, ui, repo, opts):
   123         super(jsonformatter, self).__init__(ui, repo, opts)
   129         super(jsonformatter, self).__init__(ui, repo, opts)
   124         self.ui.write('[')
   130         self.ui.write('[')
   125         self.needcomma = False
   131         self.needcomma = False
   126 
   132 
   127     def write(self, annotatedresult, lines=None, existinglines=None):
   133     def write(self, annotatedresult, lines=None, existinglines=None):
   128         if annotatedresult:
   134         if annotatedresult:
   129             self._writecomma()
   135             self._writecomma()
   130 
   136 
   131         pieces = [(name, pycompat.maplist(f, annotatedresult))
   137         pieces = [
   132                   for f, sep, name, enc in self.funcmap]
   138             (name, pycompat.maplist(f, annotatedresult))
       
   139             for f, sep, name, enc in self.funcmap
       
   140         ]
   133         if lines is not None:
   141         if lines is not None:
   134             pieces.append(('line', lines))
   142             pieces.append(('line', lines))
   135         pieces.sort()
   143         pieces.sort()
   136 
   144 
   137         seps = [','] * len(pieces[:-1]) + ['']
   145         seps = [','] * len(pieces[:-1]) + ['']
   140         lasti = len(annotatedresult) - 1
   148         lasti = len(annotatedresult) - 1
   141         for i in pycompat.xrange(len(annotatedresult)):
   149         for i in pycompat.xrange(len(annotatedresult)):
   142             result += '\n {\n'
   150             result += '\n {\n'
   143             for j, p in enumerate(pieces):
   151             for j, p in enumerate(pieces):
   144                 k, vs = p
   152                 k, vs = p
   145                 result += ('  "%s": %s%s\n'
   153                 result += '  "%s": %s%s\n' % (
   146                            % (k, templatefilters.json(vs[i], paranoid=False),
   154                     k,
   147                               seps[j]))
   155                     templatefilters.json(vs[i], paranoid=False),
       
   156                     seps[j],
       
   157                 )
   148             result += ' }%s' % ('' if i == lasti else ',')
   158             result += ' }%s' % ('' if i == lasti else ',')
   149         if lasti >= 0:
   159         if lasti >= 0:
   150             self.needcomma = True
   160             self.needcomma = True
   151 
   161 
   152         self.ui.write(result)
   162         self.ui.write(result)