Patchwork [1,of,5] templater: add public parseexpr() function to parse "-Tjson(...)"

login
register
mail settings
Submitter Yuya Nishihara
Date Oct. 6, 2019, 8 p.m.
Message ID <49e17f9f1885bd91aa2a.1570392012@mimosa>
Download mbox | patch
Permalink /patch/42042/
State Accepted
Headers show

Comments

Yuya Nishihara - Oct. 6, 2019, 8 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1570304858 14400
#      Sat Oct 05 15:47:38 2019 -0400
# Node ID 49e17f9f1885bd91aa2aa284ae4d1847b99adf59
# Parent  fdfe5cfb37236c0a5d6290578fe1d39ff95ed1bb
templater: add public parseexpr() function to parse "-Tjson(...)"

Extracted _addparseerrorhint() to show nicer hint on error.

Patch

diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -299,24 +299,27 @@  def _scantemplate(tmpl, start, stop, quo
         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
 
@@ -359,22 +362,30 @@  def parse(tmpl):
     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):