formatter: add fm.nested(field) to either write or build sub items
authorYuya Nishihara <yuya@tcha.org>
Sun, 13 Mar 2016 19:59:39 +0900
changeset 29848 5b886289a1ca
parent 29847 18bac830eef3
child 29849 8540133f91a1
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.
mercurial/formatter.py
--- 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