changeset 37500:8bb3899a0f47

formatter: make nested items somewhat readable in template output
author Yuya Nishihara <yuya@tcha.org>
date Thu, 15 Mar 2018 22:27:16 +0900
parents 75c13343cf38
children 0f4de9c27973
files mercurial/commands.py mercurial/formatter.py tests/test-annotate.t tests/test-extension.t tests/test-grep.t tests/test-identify.t
diffstat 6 files changed, 54 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/commands.py	Sun Mar 18 23:36:52 2018 +0900
+++ b/mercurial/commands.py	Thu Mar 15 22:27:16 2018 +0900
@@ -386,7 +386,7 @@
                          % ((pats and m.rel(abs)) or abs))
             continue
 
-        fm = rootfm.nested('lines')
+        fm = rootfm.nested('lines', tmpl='{rev}: {line}')
         lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
                               diffopts=diffopts)
         if not lines:
@@ -2506,7 +2506,7 @@
                 if not opts.get('text') and binary():
                     fm.plain(_(" Binary file matches"))
                 else:
-                    displaymatches(fm.nested('texts'), l)
+                    displaymatches(fm.nested('texts', tmpl='{text}'), l)
             fm.plain(eol)
             found = True
             if opts.get('files_with_matches'):
@@ -2848,7 +2848,7 @@
                 numoutput = ["%d" % p.rev() for p in parents]
                 output.append("%s%s" % ('+'.join(numoutput), dirty))
 
-            fn = fm.nested('parents')
+            fn = fm.nested('parents', tmpl='{rev}:{node|formatnode}', sep=' ')
             for p in parents:
                 fn.startitem()
                 fn.data(rev=p.rev())
@@ -5615,7 +5615,7 @@
         names.append(name)
         vers.append(extensions.moduleversion(module) or None)
         isinternals.append(extensions.ismoduleinternal(module))
-    fn = fm.nested("extensions")
+    fn = fm.nested("extensions", tmpl='{name}\n')
     if names:
         namefmt = "  %%-%ds  " % max(len(n) for n in names)
         places = [_("external"), _("internal")]
--- a/mercurial/formatter.py	Sun Mar 18 23:36:52 2018 +0900
+++ b/mercurial/formatter.py	Thu Mar 15 22:27:16 2018 +0900
@@ -95,7 +95,7 @@
 >>> def subrepos(ui, fm):
 ...     fm.startitem()
 ...     fm.write(b'reponame', b'[%s]\\n', b'baz')
-...     files(ui, fm.nested(b'files'))
+...     files(ui, fm.nested(b'files', tmpl=b'{reponame}'))
 ...     fm.end()
 >>> show(subrepos)
 [baz]
@@ -138,6 +138,10 @@
     storecontext = False
 
     @staticmethod
+    def wrapnested(data, tmpl, sep):
+        '''wrap nested data by appropriate type'''
+        return data
+    @staticmethod
     def formatdate(date, fmt):
         '''convert date tuple to appropriate format'''
         return date
@@ -210,9 +214,10 @@
     def isplain(self):
         '''check for plain formatter usage'''
         return False
-    def nested(self, field):
+    def nested(self, field, tmpl=None, sep=''):
         '''sub formatter to store nested data in the specified field'''
-        self._item[field] = data = []
+        data = []
+        self._item[field] = self._converter.wrapnested(data, tmpl, sep)
         return _nestedformatter(self._ui, self._converter, data)
     def end(self):
         '''end output for the formatter'''
@@ -243,6 +248,9 @@
     storecontext = False
 
     @staticmethod
+    def wrapnested(data, tmpl, sep):
+        raise error.ProgrammingError('plainformatter should never be nested')
+    @staticmethod
     def formatdate(date, fmt):
         '''stringify date tuple in the given format'''
         return dateutil.datestr(date, fmt)
@@ -290,7 +298,7 @@
         self._write(text, **opts)
     def isplain(self):
         return True
-    def nested(self, field):
+    def nested(self, field, tmpl=None, sep=''):
         # nested data will be directly written to ui
         return self
     def end(self):
@@ -350,6 +358,10 @@
     storecontext = True
 
     @staticmethod
+    def wrapnested(data, tmpl, sep):
+        '''wrap nested data by templatable type'''
+        return templateutil.mappinglist(data, tmpl=tmpl, sep=sep)
+    @staticmethod
     def formatdate(date, fmt):
         '''return date tuple'''
         return date
--- a/tests/test-annotate.t	Sun Mar 18 23:36:52 2018 +0900
+++ b/tests/test-annotate.t	Thu Mar 15 22:27:16 2018 +0900
@@ -90,6 +90,28 @@
   > EOF
   $ hg ci -mb2 -d '2 0'
 
+default output of '{lines}' should be readable
+
+  $ hg annotate -T'{lines}' a
+  0: a
+  1: a
+  1: a
+  $ hg annotate -T'{join(lines, "\n")}' a
+  0: a
+  
+  1: a
+  
+  1: a
+
+several filters can be applied to '{lines}'
+
+  $ hg annotate -T'{lines|stringify}' a
+  0: a
+  1: a
+  1: a
+  $ hg annotate -T'{lines|count}\n' a
+  3
+
 annotate multiple files (JSON)
 
   $ hg annotate -Tjson a b
--- a/tests/test-extension.t	Sun Mar 18 23:36:52 2018 +0900
+++ b/tests/test-extension.t	Thu Mar 15 22:27:16 2018 +0900
@@ -1407,6 +1407,11 @@
   $ hg version -q --config extensions.throw=throw.py
   Mercurial Distributed SCM (version *) (glob)
 
+Test template output:
+
+  $ hg version --config extensions.strip= -T'{extensions}'
+  strip
+
 Test JSON output of version:
 
   $ hg version -Tjson
--- a/tests/test-grep.t	Sun Mar 18 23:36:52 2018 +0900
+++ b/tests/test-grep.t	Thu Mar 15 22:27:16 2018 +0900
@@ -48,6 +48,11 @@
   port:4:914fa752cdea:vaPORTight
   port:4:914fa752cdea:imPORT/exPORT
 
+  $ hg grep port -T '{file}:{rev}:{texts}\n'
+  port:4:export
+  port:4:vaportight
+  port:4:import/export
+
 simple JSON (no "change" field)
 
   $ hg grep -Tjson port
--- a/tests/test-identify.t	Sun Mar 18 23:36:52 2018 +0900
+++ b/tests/test-identify.t	Thu Mar 15 22:27:16 2018 +0900
@@ -62,6 +62,8 @@
   2147483647 ffff
   $ hg id -T '{parents % "{rev} {node|shortest} {desc}\n"}'
   0 cb9a a
+  $ hg id -T '{parents}\n'
+  0:cb9a9f314b8b
 
 test nested template: '{tags}'/'{node}' constants shouldn't override the
 default keywords, but '{id}' persists because there's no default keyword