[PATCH 2 of 5] formatter: add fm.nested(field) to either write or build sub items

Yuya Nishihara yuya at tcha.org
Mon Aug 22 10:44:34 EDT 2016


# HG changeset patch
# User Yuya Nishihara <yuya at tcha.org>
# Date 1457866779 -32400
#      Sun Mar 13 19:59:39 2016 +0900
# Node ID 22b19113435d7e2d0dd0eb8a515d131f2552b8ac
# Parent  194ac3287b843cad7bf3d21f4f17ac901b070dea
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.

diff --git a/mercurial/formatter.py b/mercurial/formatter.py
--- a/mercurial/formatter.py
+++ b/mercurial/formatter.py
@@ -91,11 +91,23 @@ class baseformatter(object):
     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 @@ class plainformatter(baseformatter):
             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
 


More information about the Mercurial-devel mailing list