templater: strip single backslash before quotation mark in quoted template
db7463aa080f fixed the issue of double escapes, but it made the following
template fail with syntax error because of <\">. Strictly speaking, <\">
appears to be invalid in non-string part, but we are likely to escape <">
if surrounded by quotes, and we are used to write such templates by trial
and error.
[templates]
sl = "{tags % \"{ifeq(tag,'tip','',label('log.tag', ' {tag}'))}\"}"
So, for backward compatibility between 2.8.1 and 3.4, a single backslash
before quotation mark is stripped only in quoted template. We don't care
for <\"> in string literal in quoted template, which never worked as expected
before.
template result
--------- ------------------------
{\"\"} parse error
"{""}" {""} -> <>
"{\"\"}" {""} -> <>
{"\""} {"\""} -> <">
'{"\""}' {"\""} -> <">
"{"\""}" parse error (don't care)
--- a/mercurial/templater.py Thu May 07 23:18:48 2015 -0700
+++ b/mercurial/templater.py Fri May 08 18:11:26 2015 +0900
@@ -623,7 +623,21 @@
if quoted:
if len(s) < 2 or s[0] != s[-1]:
raise SyntaxError(_('unmatched quotes'))
- return s[1:-1]
+ # de-backslash-ify only <\">. it is invalid syntax in non-string part of
+ # template, but we are likely to escape <"> in quoted string and it was
+ # accepted before, thanks to issue4290. <\\"> is unmodified because it
+ # is ambiguous and it was processed as such before 2.8.1.
+ #
+ # template result
+ # --------- ------------------------
+ # {\"\"} parse error
+ # "{""}" {""} -> <>
+ # "{\"\"}" {""} -> <>
+ # {"\""} {"\""} -> <">
+ # '{"\""}' {"\""} -> <">
+ # "{"\""}" parse error (don't care)
+ q = s[0]
+ return s[1:-1].replace('\\\\' + q, '\\\\\\' + q).replace('\\' + q, q)
return s
--- a/tests/test-command-template.t Thu May 07 23:18:48 2015 -0700
+++ b/tests/test-command-template.t Fri May 08 18:11:26 2015 +0900
@@ -2313,6 +2313,25 @@
<>\n<]>
<>\n<
+Test exception in quoted template. single backslash before quotation mark is
+stripped before parsing:
+
+ $ cat <<'EOF' > escquotetmpl
+ > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
+ > EOF
+ $ cd latesttag
+ $ hg log -r 2 --style ../escquotetmpl
+ " \" \" \\" head1
+
+ $ hg log -r 2 -T esc --config templates.esc='{\"invalid\"}\n'
+ hg: parse error at 1: syntax error
+ [255]
+ $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
+ valid
+ $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
+ valid
+ $ cd ..
+
Test leading backslashes:
$ cd latesttag