Patchwork [2,of,2,STABLE] templater: strictly parse leading backslashes of '{' (issue4569) (BC)

login
register
mail settings
Submitter Yuya Nishihara
Date May 4, 2015, 11:55 p.m.
Message ID <857aebf5480deab7751d.1430783712@mimosa>
Download mbox | patch
Permalink /patch/8884/
State Accepted
Headers show

Comments

Yuya Nishihara - May 4, 2015, 11:55 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1430702254 -32400
#      Mon May 04 10:17:34 2015 +0900
# Branch stable
# Node ID 857aebf5480deab7751de93e42d93237b09b838d
# Parent  888d7a553f2b0ace8563ea9e3ef3ab1b8a50923e
templater: strictly parse leading backslashes of '{' (issue4569) (BC)

Because double backslashes are processed as a string escape sequence, '\\{'
should start the template syntax. On the other hand, r'' disables any sort
of \-escapes, so r'\{' can go either way, never start the template syntax
or always start it. I simply chose the latter, which means r'\{' is the same
as '\\{'.
Matt Mackall - May 6, 2015, 10:02 p.m.
On Tue, 2015-05-05 at 08:55 +0900, Yuya Nishihara wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1430702254 -32400
> #      Mon May 04 10:17:34 2015 +0900
> # Branch stable
> # Node ID 857aebf5480deab7751de93e42d93237b09b838d
> # Parent  888d7a553f2b0ace8563ea9e3ef3ab1b8a50923e
> templater: strictly parse leading backslashes of '{' (issue4569) (BC)
> 
> Because double backslashes are processed as a string escape sequence, '\\{'
> should start the template syntax. On the other hand, r'' disables any sort
> of \-escapes, so r'\{' can go either way, never start the template syntax
> or always start it. I simply chose the latter, which means r'\{' is the same
> as '\\{'.

These are queued for stable, thanks.

Patch

diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -87,8 +87,9 @@  def compiletemplate(tmpl, context, strto
         if n < 0:
             parsed.append((strtoken, tmpl[pos:]))
             break
-        if n > 0 and tmpl[n - 1] == '\\':
-            # escaped
+        bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
+        if strtoken == 'string' and bs % 2 == 1:
+            # escaped (e.g. '\{', '\\\{', but not '\\{' nor r'\{')
             parsed.append((strtoken, (tmpl[pos:n - 1] + "{")))
             pos = n + 1
             continue
diff --git a/tests/test-command-template.t b/tests/test-command-template.t
--- a/tests/test-command-template.t
+++ b/tests/test-command-template.t
@@ -2273,6 +2273,17 @@  Test string escaping:
   <>\n<]>
   <>\n<
 
+Test leading backslashes:
+
+  $ cd latesttag
+  $ hg log -r 2 -T '\{rev} {files % "\{file}"} {files % r"\{file}"}\n'
+  {rev} {file} \head1
+  $ hg log -r 2 -T '\\{rev} {files % "\\{file}"} {files % r"\\{file}"}\n'
+  \2 \head1 \\head1
+  $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"} {files % r"\\\{file}"}\n'
+  \{rev} \{file} \\\head1
+  $ cd ..
+
 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
 
   $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'