diff mercurial/templatefuncs.py @ 40951: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
line wrap: on
line diff
--- a/mercurial/templatefuncs.py	Fri Nov 30 00:44:04 2018 +0100
+++ b/mercurial/templatefuncs.py	Wed Dec 12 22:19:57 2018 +0900
@@ -20,6 +20,7 @@
     error,
     minirst,
     obsutil,
+    pycompat,
     registrar,
     revset as revsetmod,
     revsetlang,
@@ -581,6 +582,40 @@
 
     return minirst.format(text, style=style, keep=['verbose'])
 
+@templatefunc('search(pattern, text)')
+def search(context, mapping, args):
+    """Look for the first text matching the regular expression pattern.
+    Groups are accessible as ``{1}``, ``{2}``, ... in %-mapped template."""
+    if len(args) != 2:
+        # i18n: "search" is a keyword
+        raise error.ParseError(_(b'search expects two arguments'))
+
+    pat = evalstring(context, mapping, args[0])
+    src = evalstring(context, mapping, args[1])
+    try:
+        patre = re.compile(pat)
+    except re.error:
+        # i18n: "search" is a keyword
+        raise error.ParseError(_(b'search got an invalid pattern: %s') % pat)
+    # named groups shouldn't shadow *reserved* resource keywords
+    badgroups = (context.knownresourcekeys()
+                 & set(pycompat.byteskwargs(patre.groupindex)))
+    if badgroups:
+        raise error.ParseError(
+            # i18n: "search" is a keyword
+            _(b'invalid group %(group)s in search pattern: %(pat)s')
+            % {b'group': b', '.join("'%s'" % g for g in sorted(badgroups)),
+               b'pat': pat})
+
+    match = patre.search(src)
+    if not match:
+        return
+
+    lm = {b'0': match.group(0)}
+    lm.update((b'%d' % i, v) for i, v in enumerate(match.groups(), 1))
+    lm.update(pycompat.byteskwargs(match.groupdict()))
+    return templateutil.mappingdict(lm, tmpl=b'{0}')
+
 @templatefunc('separate(sep, args...)', argspec='sep *args')
 def separate(context, mapping, args):
     """Add a separator between non-empty arguments."""