mercurial/revsetlang.py
changeset 41219 e5b227f41e4a
parent 41218 24a1f67bb75a
child 41220 8d26026b3335
--- a/mercurial/revsetlang.py	Thu Jan 10 15:23:58 2019 +0100
+++ b/mercurial/revsetlang.py	Fri Jan 04 02:29:04 2019 +0100
@@ -666,6 +666,23 @@
     >>> formatspec(b'%ls', [b'a', b"'"])
     "_list('a\\\\x00\\\\'')"
     '''
+    parsed = _parseargs(expr, args)
+    ret = []
+    for t, arg in parsed:
+        if t is None:
+            ret.append(arg)
+        else:
+            raise error.ProgrammingError("unknown revspec item type: %r" % t)
+    return b''.join(ret)
+
+def _parseargs(expr, args):
+    """parse the expression and replace all inexpensive args
+
+    return a list of tuple [(arg-type, arg-value)]
+
+    Arg-type can be:
+    * None: a string ready to be concatenated into a final spec
+    """
     expr = pycompat.bytestr(expr)
     argiter = iter(args)
     ret = []
@@ -673,16 +690,16 @@
     while pos < len(expr):
         q = expr.find('%', pos)
         if q < 0:
-            ret.append(expr[pos:])
+            ret.append((None, expr[pos:]))
             break
-        ret.append(expr[pos:q])
+        ret.append((None, expr[pos:q]))
         pos = q + 1
         try:
             d = expr[pos]
         except IndexError:
             raise error.ParseError(_('incomplete revspec format character'))
         if d == '%':
-            ret.append(d)
+            ret.append((None, d))
             pos += 1
             continue
 
@@ -692,19 +709,20 @@
             raise error.ParseError(_('missing argument for revspec'))
         f = _formatlistfuncs.get(d)
         if f:
-            # a list of some type
+            # a list of some type, might be expensive, do not replace
             pos += 1
             try:
                 d = expr[pos]
             except IndexError:
                 raise error.ParseError(_('incomplete revspec format character'))
             try:
-                ret.append(f(list(arg), d))
+                ret.append((None, f(list(arg), d)))
             except (TypeError, ValueError):
                 raise error.ParseError(_('invalid argument for revspec'))
         else:
+            # a single entry, not expensive, replace
             try:
-                ret.append(_formatargtype(d, arg))
+                ret.append((None, _formatargtype(d, arg)))
             except (TypeError, ValueError):
                 raise error.ParseError(_('invalid argument for revspec'))
         pos += 1
@@ -714,7 +732,7 @@
         raise error.ParseError(_('too many revspec arguments specified'))
     except StopIteration:
         pass
-    return ''.join(ret)
+    return ret
 
 def prettyformat(tree):
     return parser.prettyformat(tree, ('string', 'symbol'))