# HG changeset patch
# User Matt Harbison <matt_harbi...@yahoo.com>
# Date 1483842392 18000
#      Sat Jan 07 21:26:32 2017 -0500
# Node ID 7347f75339503a8266285ac12412ac5f104d4df0
# Parent  4ab19763d71c2bb9a239dff523b18ed860e34563
revset: add regular expression support to 'desc()'

The legacy behavior of doing a case insensitive match for literals is preserved
for BC.  This includes with the new 'literal:' prefix for user simplicity.

There are two other revsets that do case insensitive matches- 'user()' (and its
alias 'author()'), and 'keyword()'.  The 'keyword()' predicate only supports
literals, so its behavior isn't interesting right now.  The 'user()' predicate
is documented to support regex, but ends up lowercasing both the needle and the
haystack, effectively making it a case insensitive regex.  That surprised me,
since it's the only instance of that behavior.  I'm not sure if this should
conform to that because we are stuck with BC, or if that should be considered a
bug and changed.  If we can't change it, that probably precludes adding an
insensitive regex matcher [1].

[1] 
https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-January/092070.html

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -813,16 +813,25 @@
 
 @predicate('desc(string)', safe=True)
 def desc(repo, subset, x):
-    """Search commit message for string. The match is case-insensitive.
+    """Search commit message for string. The match for a literal is
+    case-insensitive.
+
+    If `string` starts with `re:`, the remainder of the string is treated as
+    a regular expression. To match a substring that actually starts with `re:`,
+    use the prefix `literal:`.
     """
     # i18n: "desc" is a keyword
-    ds = encoding.lower(getstring(x, _("desc requires a string")))
-
-    def matches(x):
-        c = repo[x]
-        return ds in encoding.lower(c.description())
-
-    return subset.filter(matches, condrepr=('<desc %r>', ds))
+    ds = getstring(x, _("desc requires a string"))
+
+    kind, pattern, matcher = util.stringmatcher(ds)
+
+    if kind == 'literal':
+        # Legacy icase substring behavior for literal patterns.
+        ds = encoding.lower(pattern)
+        matcher = lambda s: ds in encoding.lower(s)
+
+    return subset.filter(lambda x: matcher(repo[x].description()),
+                         condrepr=('<desc %r>', ds))
 
 def _descendants(repo, subset, x, followfirst=False):
     roots = getset(repo, fullreposet(repo), x)
diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -901,6 +901,10 @@
   5
   $ log 'desc(B)'
   5
+  $ log 'desc("re:[a-z]")'
+  5
+  6
+  9
   $ log 'descendants(2 or 3)'
   2
   3
_______________________________________________
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Reply via email to