changeset 43098:9691fc764bdc

templater: add public parseexpr() function to parse "-Tjson(...)" Extracted _addparseerrorhint() to show nicer hint on error.
author Yuya Nishihara <yuya@tcha.org>
date Sat, 05 Oct 2019 15:47:38 -0400
parents 27c4f93d07a9
children f1c5358f0d65
files mercurial/templater.py
diffstat 1 files changed, 30 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/templater.py	Sun Oct 06 13:06:19 2019 +0200
+++ b/mercurial/templater.py	Sat Oct 05 15:47:38 2019 -0400
@@ -300,24 +300,27 @@
         if quote:
             raise error.ParseError(_(b"unterminated string"), start)
     except error.ParseError as inst:
-        if len(inst.args) > 1:  # has location
-            loc = inst.args[1]
-            # Offset the caret location by the number of newlines before the
-            # location of the error, since we will replace one-char newlines
-            # with the two-char literal r'\n'.
-            offset = tmpl[:loc].count(b'\n')
-            tmpl = tmpl.replace(b'\n', br'\n')
-            # We want the caret to point to the place in the template that
-            # failed to parse, but in a hint we get a open paren at the
-            # start. Therefore, we print "loc + 1" spaces (instead of "loc")
-            # to line up the caret with the location of the error.
-            inst.hint = (
-                tmpl + b'\n' + b' ' * (loc + 1 + offset) + b'^ ' + _(b'here')
-            )
+        _addparseerrorhint(inst, tmpl)
         raise
     yield (b'end', None, pos)
 
 
+def _addparseerrorhint(inst, tmpl):
+    if len(inst.args) <= 1:
+        return  # no location
+    loc = inst.args[1]
+    # Offset the caret location by the number of newlines before the
+    # location of the error, since we will replace one-char newlines
+    # with the two-char literal r'\n'.
+    offset = tmpl[:loc].count(b'\n')
+    tmpl = tmpl.replace(b'\n', br'\n')
+    # We want the caret to point to the place in the template that
+    # failed to parse, but in a hint we get a open paren at the
+    # start. Therefore, we print "loc + 1" spaces (instead of "loc")
+    # to line up the caret with the location of the error.
+    inst.hint = tmpl + b'\n' + b' ' * (loc + 1 + offset) + b'^ ' + _(b'here')
+
+
 def _unnesttemplatelist(tree):
     """Expand list of templates to node tuple
 
@@ -360,22 +363,30 @@
     return _unnesttemplatelist((b'template', parsed))
 
 
-def _parseexpr(expr):
+def parseexpr(expr):
     """Parse a template expression into tree
 
-    >>> _parseexpr(b'"foo"')
+    >>> parseexpr(b'"foo"')
     ('string', 'foo')
-    >>> _parseexpr(b'foo(bar)')
+    >>> parseexpr(b'foo(bar)')
     ('func', ('symbol', 'foo'), ('symbol', 'bar'))
-    >>> _parseexpr(b'foo(')
+    >>> parseexpr(b'foo(')
     Traceback (most recent call last):
       ...
     ParseError: ('not a prefix: end', 4)
-    >>> _parseexpr(b'"foo" "bar"')
+    >>> parseexpr(b'"foo" "bar"')
     Traceback (most recent call last):
       ...
     ParseError: ('invalid token', 7)
     """
+    try:
+        return _parseexpr(expr)
+    except error.ParseError as inst:
+        _addparseerrorhint(inst, expr)
+        raise
+
+
+def _parseexpr(expr):
     p = parser.parser(elements)
     tree, pos = p.parse(tokenize(expr, 0, len(expr)))
     if pos != len(expr):