Mercurial > hg
view mercurial/formatter.py @ 28627:d7af9b4ae7dd
graphmod: set default edge styles for ascii graphs (BC)
Leaving regular parent edges set to |, grandparent edges set to : and missing
parent edges set to end early. A sample graph:
o changeset: 32:d06dffa21a31
|\ parent: 27:886ed638191b
| : parent: 31:621d83e11f67
| :
o : changeset: 31:621d83e11f67
|\: parent: 21:d42a756af44d
| : parent: 30:6e11cd4b648f
| :
o : changeset: 30:6e11cd4b648f
|\ \ parent: 28:44ecd0b9ae99
| ~ : parent: 29:cd9bb2be7593
| /
o : changeset: 28:44ecd0b9ae99
|\ \ parent: 1:6db2ef61d156
| ~ : parent: 26:7f25b6c2f0b9
| /
o : changeset: 26:7f25b6c2f0b9
|\ \ parent: 18:1aa84d96232a
| | : parent: 25:91da8ed57247
| | :
| o : changeset: 25:91da8ed57247
| |\: parent: 21:d42a756af44d
| | : parent: 24:a9c19a3d96b7
| | :
| o : changeset: 24:a9c19a3d96b7
| |\ \ parent: 0:e6eb3150255d
| | ~ : parent: 23:a01cddf0766d
| | /
| o : changeset: 23:a01cddf0766d
| |\ \ parent: 1:6db2ef61d156
| | ~ : parent: 22:e0d9cccacb5d
| | /
| o : changeset: 22:e0d9cccacb5d
|/:/ parent: 18:1aa84d96232a
| : parent: 21:d42a756af44d
| :
| o changeset: 21:d42a756af44d
| |\ parent: 19:31ddc2c1573b
| | | parent: 20:d30ed6450e32
| | |
+---o changeset: 20:d30ed6450e32
| | | parent: 0:e6eb3150255d
| | ~ parent: 18:1aa84d96232a
| |
| o changeset: 19:31ddc2c1573b
| |\ parent: 15:1dda3f72782d
| ~ ~ parent: 17:44765d7c06e0
|
o changeset: 18:1aa84d96232a
parent: 1:6db2ef61d156
parent: 15:1dda3f72782d
author | Martijn Pieters <mjpieters@fb.com> |
---|---|
date | Wed, 23 Mar 2016 13:34:47 -0700 |
parents | 3356bf61fa25 |
children | bf35644b9f3a |
line wrap: on
line source
# formatter.py - generic output formatting for mercurial # # Copyright 2012 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. from __future__ import absolute_import import cPickle import os from .i18n import _ from .node import ( hex, short, ) from . import ( encoding, error, templater, ) class baseformatter(object): def __init__(self, ui, topic, opts): self._ui = ui self._topic = topic self._style = opts.get("style") self._template = opts.get("template") self._item = None # function to convert node to string suitable for this output self.hexfunc = hex def __nonzero__(self): '''return False if we're not doing real templating so we can skip extra work''' return True def _showitem(self): '''show a formatted item once all data is collected''' pass def startitem(self): '''begin an item in the format list''' if self._item is not None: self._showitem() self._item = {} def data(self, **data): '''insert data into item that's not shown in default output''' self._item.update(data) def write(self, fields, deftext, *fielddata, **opts): '''do default text output while assigning data to item''' fieldkeys = fields.split() assert len(fieldkeys) == len(fielddata) self._item.update(zip(fieldkeys, fielddata)) def condwrite(self, cond, fields, deftext, *fielddata, **opts): '''do conditional write (primarily for plain formatter)''' fieldkeys = fields.split() assert len(fieldkeys) == len(fielddata) self._item.update(zip(fieldkeys, fielddata)) def plain(self, text, **opts): '''show raw text for non-templated mode''' pass def end(self): '''end output for the formatter''' if self._item is not None: self._showitem() class plainformatter(baseformatter): '''the default text output scheme''' def __init__(self, ui, topic, opts): baseformatter.__init__(self, ui, topic, opts) if ui.debugflag: self.hexfunc = hex else: self.hexfunc = short def __nonzero__(self): return False def startitem(self): pass def data(self, **data): pass def write(self, fields, deftext, *fielddata, **opts): self._ui.write(deftext % fielddata, **opts) def condwrite(self, cond, fields, deftext, *fielddata, **opts): '''do conditional write''' if cond: self._ui.write(deftext % fielddata, **opts) def plain(self, text, **opts): self._ui.write(text, **opts) def end(self): pass class debugformatter(baseformatter): def __init__(self, ui, topic, opts): baseformatter.__init__(self, ui, topic, opts) self._ui.write("%s = [\n" % self._topic) def _showitem(self): self._ui.write(" " + repr(self._item) + ",\n") def end(self): baseformatter.end(self) self._ui.write("]\n") class pickleformatter(baseformatter): def __init__(self, ui, topic, opts): baseformatter.__init__(self, ui, topic, opts) self._data = [] def _showitem(self): self._data.append(self._item) def end(self): baseformatter.end(self) self._ui.write(cPickle.dumps(self._data)) def _jsonifyobj(v): if isinstance(v, tuple): return '[' + ', '.join(_jsonifyobj(e) for e in v) + ']' elif v is None: return 'null' elif v is True: return 'true' elif v is False: return 'false' elif isinstance(v, (int, float)): return str(v) else: return '"%s"' % encoding.jsonescape(v) class jsonformatter(baseformatter): def __init__(self, ui, topic, opts): baseformatter.__init__(self, ui, topic, opts) self._ui.write("[") self._ui._first = True def _showitem(self): if self._ui._first: self._ui._first = False else: self._ui.write(",") self._ui.write("\n {\n") first = True for k, v in sorted(self._item.items()): if first: first = False else: self._ui.write(",\n") self._ui.write(' "%s": %s' % (k, _jsonifyobj(v))) self._ui.write("\n }") def end(self): baseformatter.end(self) self._ui.write("\n]\n") class templateformatter(baseformatter): def __init__(self, ui, topic, opts): baseformatter.__init__(self, ui, topic, opts) self._topic = topic self._t = gettemplater(ui, topic, opts.get('template', '')) def _showitem(self): g = self._t(self._topic, ui=self._ui, **self._item) self._ui.write(templater.stringify(g)) def lookuptemplate(ui, topic, tmpl): # looks like a literal template? if '{' in tmpl: return tmpl, None # perhaps a stock style? if not os.path.split(tmpl)[0]: mapname = (templater.templatepath('map-cmdline.' + tmpl) or templater.templatepath(tmpl)) if mapname and os.path.isfile(mapname): return None, mapname # perhaps it's a reference to [templates] t = ui.config('templates', tmpl) if t: try: tmpl = templater.unquotestring(t) except SyntaxError: tmpl = t return tmpl, None if tmpl == 'list': ui.write(_("available styles: %s\n") % templater.stylelist()) raise error.Abort(_("specify a template")) # perhaps it's a path to a map or a template if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl): # is it a mapfile for a style? if os.path.basename(tmpl).startswith("map-"): return None, os.path.realpath(tmpl) tmpl = open(tmpl).read() return tmpl, None # constant string? return tmpl, None def gettemplater(ui, topic, spec): tmpl, mapfile = lookuptemplate(ui, topic, spec) t = templater.templater(mapfile, {}) if tmpl: t.cache[topic] = tmpl return t def formatter(ui, topic, opts): template = opts.get("template", "") if template == "json": return jsonformatter(ui, topic, opts) elif template == "pickle": return pickleformatter(ui, topic, opts) elif template == "debug": return debugformatter(ui, topic, opts) elif template != "": return templateformatter(ui, topic, opts) # developer config: ui.formatdebug elif ui.configbool('ui', 'formatdebug'): return debugformatter(ui, topic, opts) # deprecated config: ui.formatjson elif ui.configbool('ui', 'formatjson'): return jsonformatter(ui, topic, opts) return plainformatter(ui, topic, opts)