comparison mercurial/templatefuncs.py @ 44592:7cd5c0968139

templater: add subsetparents(rev, revset) function Naming suggestions are welcome. And this could be flagged as an (ADVANCED) function since the primary use case is to draw a graph. This provides all data needed for drawing revisions graph filtered by revset, and allows us to implement a GUI graph viewer in some languages better than Python. A frontend grapher will be quite similar to our graphmod since subsetparents() just returns parent-child relations in the filtered sub graph. Frontend example: https://hg.sr.ht/~yuja/hgv/browse/default/core/hgchangesetgrapher.cpp However, the resulting graph will be simpler than the one "hg log -G" would generate because redundant edges are eliminated. This should be the same graph rendering strategy as TortoiseHg. This function could be implemented as a revset predicate, but that would mean the scanning state couldn't be cached and thus slow. Test cases are split to new file since test-template-functions.t is quite big and we'll need a new branchy repository anyway.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 15 Mar 2020 16:11:58 +0900
parents 1f81f680912f
children 89a2afe31e82
comparison
equal deleted inserted replaced
44591:1f81f680912f 44592:7cd5c0968139
14 bin, 14 bin,
15 wdirid, 15 wdirid,
16 ) 16 )
17 from . import ( 17 from . import (
18 color, 18 color,
19 dagop,
19 diffutil, 20 diffutil,
20 encoding, 21 encoding,
21 error, 22 error,
22 minirst, 23 minirst,
23 obsutil, 24 obsutil,
840 if text.startswith(patn): 841 if text.startswith(patn):
841 return text 842 return text
842 return b'' 843 return b''
843 844
844 845
846 @templatefunc(
847 b'subsetparents(rev, revset)',
848 argspec=b'rev revset',
849 requires={b'repo', b'cache'},
850 )
851 def subsetparents(context, mapping, args):
852 """Look up parents of the rev in the sub graph given by the revset."""
853 if b'rev' not in args or b'revset' not in args:
854 # i18n: "subsetparents" is a keyword
855 raise error.ParseError(_(b"subsetparents expects two arguments"))
856
857 repo = context.resource(mapping, b'repo')
858
859 rev = templateutil.evalinteger(context, mapping, args[b'rev'])
860
861 # TODO: maybe subsetparents(rev) should be allowed. the default revset
862 # will be the revisions specified by -rREV argument.
863 q = templateutil.evalwrapped(context, mapping, args[b'revset'])
864 if not isinstance(q, templateutil.revslist):
865 # i18n: "subsetparents" is a keyword
866 raise error.ParseError(_(b"subsetparents expects a queried revset"))
867 subset = q.tovalue(context, mapping)
868 key = q.cachekey
869
870 if key:
871 # cache only if revset query isn't dynamic
872 cache = context.resource(mapping, b'cache')
873 walkercache = cache.setdefault(b'subsetparentswalker', {})
874 if key in walkercache:
875 walker = walkercache[key]
876 else:
877 walker = dagop.subsetparentswalker(repo, subset)
878 walkercache[key] = walker
879 else:
880 # for one-shot use, specify startrev to limit the search space
881 walker = dagop.subsetparentswalker(repo, subset, startrev=rev)
882 return templateutil.revslist(repo, walker.parentsset(rev))
883
884
845 @templatefunc(b'word(number, text[, separator])') 885 @templatefunc(b'word(number, text[, separator])')
846 def word(context, mapping, args): 886 def word(context, mapping, args):
847 """Return the nth word from a string.""" 887 """Return the nth word from a string."""
848 if not (2 <= len(args) <= 3): 888 if not (2 <= len(args) <= 3):
849 # i18n: "word" is a keyword 889 # i18n: "word" is a keyword