formatter: add fm.nested(field) to either write or build sub items
We sometimes need to build nested items by formatter, but there was no
convenient way other than building and putting them manually by fm.data():
exts = []
for n, v in extensions:
fm.plain('%s %s\n' % (n, v))
exts.append({'name': n, 'ver': v})
fm.data(extensions=exts)
This should work for simple cases, but doing this would make it harder to
change the underlying data type for better templating support.
So this patch provides fm.nested(field), which returns new nested formatter
(or self if items aren't structured and just written to ui.) A nested formatter
stores items which will later be rendered by the parent formatter.
fn = fm.nested('extensions')
for n, v in extensions:
fn.startitem()
fn.write('name ver', '%s %s\n', n, v)
fn.end()
Nested items are directly exported to a template for now:
{extensions % "{name} {ver}\n"}
There's no {extensions} nor {join(extensions, sep)} yet. I have a plan for
them by extending fm.nested() API, but I want to revisit it after trying
out this API in the real world.
--- a/mercurial/formatter.py Mon Aug 15 13:51:14 2016 +0900
+++ b/mercurial/formatter.py Sun Mar 13 19:59:39 2016 +0900
@@ -91,11 +91,23 @@
def plain(self, text, **opts):
'''show raw text for non-templated mode'''
pass
+ def nested(self, field):
+ '''sub formatter to store nested data in the specified field'''
+ self._item[field] = data = []
+ return _nestedformatter(self._ui, self._converter, data)
def end(self):
'''end output for the formatter'''
if self._item is not None:
self._showitem()
+class _nestedformatter(baseformatter):
+ '''build sub items and store them in the parent formatter'''
+ def __init__(self, ui, converter, data):
+ baseformatter.__init__(self, ui, topic='', opts={}, converter=converter)
+ self._data = data
+ def _showitem(self):
+ self._data.append(self._item)
+
def _iteritems(data):
'''iterate key-value pairs in stable order'''
if isinstance(data, dict):
@@ -139,6 +151,9 @@
self._ui.write(deftext % fielddata, **opts)
def plain(self, text, **opts):
self._ui.write(text, **opts)
+ def nested(self, field):
+ # nested data will be directly written to ui
+ return self
def end(self):
pass