##// END OF EJS Templates
templater: add hint to template parse errors to help locate issues...
Ryan McElroy -
r36687:80d7fb6c default
parent child Browse files
Show More
@@ -213,35 +213,48 b' def _scantemplate(tmpl, start, stop, quo'
213 unescape = [parser.unescapestr, pycompat.identity][raw]
213 unescape = [parser.unescapestr, pycompat.identity][raw]
214 pos = start
214 pos = start
215 p = parser.parser(elements)
215 p = parser.parser(elements)
216 while pos < stop:
216 try:
217 n = min((tmpl.find(c, pos, stop) for c in sepchars),
217 while pos < stop:
218 key=lambda n: (n < 0, n))
218 n = min((tmpl.find(c, pos, stop) for c in sepchars),
219 if n < 0:
219 key=lambda n: (n < 0, n))
220 yield ('string', unescape(tmpl[pos:stop]), pos)
220 if n < 0:
221 pos = stop
221 yield ('string', unescape(tmpl[pos:stop]), pos)
222 break
222 pos = stop
223 c = tmpl[n:n + 1]
223 break
224 bs = 0 # count leading backslashes
224 c = tmpl[n:n + 1]
225 if not raw:
225 bs = 0 # count leading backslashes
226 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
226 if not raw:
227 if bs % 2 == 1:
227 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
228 # escaped (e.g. '\{', '\\\{', but not '\\{')
228 if bs % 2 == 1:
229 yield ('string', unescape(tmpl[pos:n - 1]) + c, pos)
229 # escaped (e.g. '\{', '\\\{', but not '\\{')
230 pos = n + 1
230 yield ('string', unescape(tmpl[pos:n - 1]) + c, pos)
231 continue
231 pos = n + 1
232 if n > pos:
232 continue
233 yield ('string', unescape(tmpl[pos:n]), pos)
233 if n > pos:
234 if c == quote:
234 yield ('string', unescape(tmpl[pos:n]), pos)
235 yield ('end', None, n + 1)
235 if c == quote:
236 return
236 yield ('end', None, n + 1)
237 return
237
238
238 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
239 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
239 if not tmpl.endswith('}', n + 1, pos):
240 if not tmpl.endswith('}', n + 1, pos):
240 raise error.ParseError(_("invalid token"), pos)
241 raise error.ParseError(_("invalid token"), pos)
241 yield ('template', parseres, n)
242 yield ('template', parseres, n)
242
243
243 if quote:
244 if quote:
244 raise error.ParseError(_("unterminated string"), start)
245 raise error.ParseError(_("unterminated string"), start)
246 except error.ParseError as inst:
247 if len(inst.args) > 1: # has location
248 loc = inst.args[1]
249 # TODO: Opportunity for improvement! If there is a newline in the
250 # template, this hint does not point to the right place, so skip.
251 if '\n' not in tmpl:
252 # We want the caret to point to the place in the template that
253 # failed to parse, but in a hint we get a open paren at the
254 # start. Therefore, we print "loc" spaces (instead of "loc - 1")
255 # to line up the caret with the location of the error.
256 inst.hint = tmpl + '\n' + ' ' * (loc) + '^ ' + _('here')
257 raise
245 yield ('end', None, pos)
258 yield ('end', None, pos)
246
259
247 def _unnesttemplatelist(tree):
260 def _unnesttemplatelist(tree):
@@ -2766,19 +2766,29 b' Error on syntax:'
2766
2766
2767 $ hg log -T '{date'
2767 $ hg log -T '{date'
2768 hg: parse error at 1: unterminated template expansion
2768 hg: parse error at 1: unterminated template expansion
2769 ({date
2770 ^ here)
2769 [255]
2771 [255]
2770 $ hg log -T '{date(}'
2772 $ hg log -T '{date(}'
2771 hg: parse error at 7: not a prefix: end
2773 hg: parse error at 7: not a prefix: end
2774 ({date(}
2775 ^ here)
2772 [255]
2776 [255]
2773 $ hg log -T '{date)}'
2777 $ hg log -T '{date)}'
2774 hg: parse error at 5: invalid token
2778 hg: parse error at 5: invalid token
2779 ({date)}
2780 ^ here)
2775 [255]
2781 [255]
2776 $ hg log -T '{date date}'
2782 $ hg log -T '{date date}'
2777 hg: parse error at 6: invalid token
2783 hg: parse error at 6: invalid token
2784 ({date date}
2785 ^ here)
2778 [255]
2786 [255]
2779
2787
2780 $ hg log -T '{}'
2788 $ hg log -T '{}'
2781 hg: parse error at 2: not a prefix: end
2789 hg: parse error at 2: not a prefix: end
2790 ({}
2791 ^ here)
2782 [255]
2792 [255]
2783 $ hg debugtemplate -v '{()}'
2793 $ hg debugtemplate -v '{()}'
2784 (template
2794 (template
@@ -2827,10 +2837,14 b' Error in nested template:'
2827
2837
2828 $ hg log -T '{"date'
2838 $ hg log -T '{"date'
2829 hg: parse error at 2: unterminated string
2839 hg: parse error at 2: unterminated string
2840 ({"date
2841 ^ here)
2830 [255]
2842 [255]
2831
2843
2832 $ hg log -T '{"foo{date|?}"}'
2844 $ hg log -T '{"foo{date|?}"}'
2833 hg: parse error at 11: syntax error
2845 hg: parse error at 11: syntax error
2846 ({"foo{date|?}"}
2847 ^ here)
2834 [255]
2848 [255]
2835
2849
2836 Thrown an error if a template function doesn't exist
2850 Thrown an error if a template function doesn't exist
@@ -3362,6 +3376,8 b' Test integer literal:'
3362 -4
3376 -4
3363 $ hg debugtemplate '{(-)}\n'
3377 $ hg debugtemplate '{(-)}\n'
3364 hg: parse error at 3: not a prefix: )
3378 hg: parse error at 3: not a prefix: )
3379 ({(-)}\n
3380 ^ here)
3365 [255]
3381 [255]
3366 $ hg debugtemplate '{(-a)}\n'
3382 $ hg debugtemplate '{(-a)}\n'
3367 hg: parse error: negation needs an integer argument
3383 hg: parse error: negation needs an integer argument
@@ -3527,6 +3543,8 b' escaped single quotes and errors:'
3527 foo
3543 foo
3528 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3544 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3529 hg: parse error at 21: unterminated string
3545 hg: parse error at 21: unterminated string
3546 ({if(rev, "{if(rev, \")}")}\n
3547 ^ here)
3530 [255]
3548 [255]
3531 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3549 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3532 hg: parse error: trailing \ in string
3550 hg: parse error: trailing \ in string
@@ -218,6 +218,8 b' Invalid pattern in file name:'
218 [255]
218 [255]
219 $ hg export -o '%m{' tip
219 $ hg export -o '%m{' tip
220 hg: parse error at 3: unterminated template expansion
220 hg: parse error at 3: unterminated template expansion
221 (%m{
222 ^ here)
221 [255]
223 [255]
222 $ hg export -o '%\' tip
224 $ hg export -o '%\' tip
223 abort: invalid format spec '%\' in output filename
225 abort: invalid format spec '%\' in output filename
@@ -2289,6 +2289,23 b' Check that adding an arbitrary name show'
2289 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
2289 $ hg --config extensions.names=../names.py log -r 0 --template '{bars}\n'
2290 foo
2290 foo
2291
2291
2292 Templater parse errors:
2293
2294 simple error
2295 $ hg log -r . -T '{shortest(node}'
2296 hg: parse error at 15: unexpected token: end
2297 ({shortest(node}
2298 ^ here)
2299 [255]
2300
2301 multi-line template with error
2302 $ hg log -r . -T 'line 1
2303 > line2
2304 > {shortest(node}
2305 > line4\nline5'
2306 hg: parse error at 28: unexpected token: end
2307 [255]
2308
2292 $ cd ..
2309 $ cd ..
2293
2310
2294 hg log -f dir across branches
2311 hg log -f dir across branches
General Comments 0
You need to be logged in to leave comments. Login now