comparison mercurial/templatefuncs.py @ 40934:d3e688b9ef2e

templatefuncs: add regexp search() function that extracts substring This can be used to extract an issue number from a commit message, for example: {search(r'\(issue([0-9]*)\)', desc) % '{1}'}
author Yuya Nishihara <yuya@tcha.org>
date Wed, 12 Dec 2018 22:19:57 +0900
parents d11e2c5b287e
children 4591c9791a82
comparison
equal deleted inserted replaced
40933:18513d6ef7d4 40934:d3e688b9ef2e
18 color, 18 color,
19 encoding, 19 encoding,
20 error, 20 error,
21 minirst, 21 minirst,
22 obsutil, 22 obsutil,
23 pycompat,
23 registrar, 24 registrar,
24 revset as revsetmod, 25 revset as revsetmod,
25 revsetlang, 26 revsetlang,
26 scmutil, 27 scmutil,
27 templatefilters, 28 templatefilters,
579 text = evalstring(context, mapping, args[0]) 580 text = evalstring(context, mapping, args[0])
580 style = evalstring(context, mapping, args[1]) 581 style = evalstring(context, mapping, args[1])
581 582
582 return minirst.format(text, style=style, keep=['verbose']) 583 return minirst.format(text, style=style, keep=['verbose'])
583 584
585 @templatefunc('search(pattern, text)')
586 def search(context, mapping, args):
587 """Look for the first text matching the regular expression pattern.
588 Groups are accessible as ``{1}``, ``{2}``, ... in %-mapped template."""
589 if len(args) != 2:
590 # i18n: "search" is a keyword
591 raise error.ParseError(_(b'search expects two arguments'))
592
593 pat = evalstring(context, mapping, args[0])
594 src = evalstring(context, mapping, args[1])
595 try:
596 patre = re.compile(pat)
597 except re.error:
598 # i18n: "search" is a keyword
599 raise error.ParseError(_(b'search got an invalid pattern: %s') % pat)
600 # named groups shouldn't shadow *reserved* resource keywords
601 badgroups = (context.knownresourcekeys()
602 & set(pycompat.byteskwargs(patre.groupindex)))
603 if badgroups:
604 raise error.ParseError(
605 # i18n: "search" is a keyword
606 _(b'invalid group %(group)s in search pattern: %(pat)s')
607 % {b'group': b', '.join("'%s'" % g for g in sorted(badgroups)),
608 b'pat': pat})
609
610 match = patre.search(src)
611 if not match:
612 return
613
614 lm = {b'0': match.group(0)}
615 lm.update((b'%d' % i, v) for i, v in enumerate(match.groups(), 1))
616 lm.update(pycompat.byteskwargs(match.groupdict()))
617 return templateutil.mappingdict(lm, tmpl=b'{0}')
618
584 @templatefunc('separate(sep, args...)', argspec='sep *args') 619 @templatefunc('separate(sep, args...)', argspec='sep *args')
585 def separate(context, mapping, args): 620 def separate(context, mapping, args):
586 """Add a separator between non-empty arguments.""" 621 """Add a separator between non-empty arguments."""
587 if 'sep' not in args: 622 if 'sep' not in args:
588 # i18n: "separate" is a keyword 623 # i18n: "separate" is a keyword