mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
escape sequences now use $ instead of doubling
This was causing a problem with situation where }} would have semantic meaning
other than escaping a }. Specifically, %func{%func{arg}} contains a }} but
should not escape the }. $} seems to cover this situation. However, ${ is not
permitted as an escape sequence because it looks like the beginning of a symbol
(variable reference) like ${foo}. This is OK because { can be used anywhere as a
literal.
This commit is contained in:
parent
829bd14993
commit
ae2f0db540
2 changed files with 16 additions and 13 deletions
|
|
@ -32,6 +32,7 @@ FUNC_DELIM = u'%'
|
|||
GROUP_OPEN = u'{'
|
||||
GROUP_CLOSE = u'}'
|
||||
ARG_SEP = u','
|
||||
ESCAPE_CHAR = u'$'
|
||||
|
||||
class Environment(object):
|
||||
"""Contains the values and functions to be substituted into a
|
||||
|
|
@ -139,7 +140,7 @@ class Parser(object):
|
|||
char = self.string[self.pos]
|
||||
|
||||
if char not in (SYMBOL_DELIM, FUNC_DELIM, GROUP_OPEN,
|
||||
GROUP_CLOSE, ARG_SEP):
|
||||
GROUP_CLOSE, ARG_SEP, ESCAPE_CHAR):
|
||||
# A non-special character.
|
||||
# TODO: This can be made more efficient by repeatedly asking
|
||||
# for the next special character rather than walking through
|
||||
|
|
@ -158,9 +159,13 @@ class Parser(object):
|
|||
break
|
||||
|
||||
next_char = self.string[self.pos + 1]
|
||||
if char == next_char:
|
||||
# An escaped special character ($$, etc.).
|
||||
text_parts.append(char)
|
||||
if char == ESCAPE_CHAR and next_char in \
|
||||
(SYMBOL_DELIM, FUNC_DELIM, GROUP_CLOSE, ARG_SEP):
|
||||
# An escaped special character ($$, $}, etc.). Note that
|
||||
# ${ is not an escape sequence: this is ambiguous with
|
||||
# the start of a symbol and it's not necessary (just
|
||||
# using { suffices in all cases).
|
||||
text_parts.append(next_char)
|
||||
self.pos += 2 # Skip the next character.
|
||||
continue
|
||||
|
||||
|
|
|
|||
|
|
@ -86,16 +86,13 @@ class ParseTest(unittest.TestCase):
|
|||
self.assertEqual(list(_normparse(u'hello $$')), [u'hello $'])
|
||||
|
||||
def test_escaped_function_delim(self):
|
||||
self.assertEqual(list(_normparse(u'a %% b')), [u'a % b'])
|
||||
self.assertEqual(list(_normparse(u'a $% b')), [u'a % b'])
|
||||
|
||||
def test_escaped_sep(self):
|
||||
self.assertEqual(list(_normparse(u'a ,, b')), [u'a , b'])
|
||||
|
||||
def test_escaped_open_brace(self):
|
||||
self.assertEqual(list(_normparse(u'a {{ b')), [u'a { b'])
|
||||
self.assertEqual(list(_normparse(u'a $, b')), [u'a , b'])
|
||||
|
||||
def test_escaped_close_brace(self):
|
||||
self.assertEqual(list(_normparse(u'a }} b')), [u'a } b'])
|
||||
self.assertEqual(list(_normparse(u'a $} b')), [u'a } b'])
|
||||
|
||||
def test_bare_value_delim_kept_intact(self):
|
||||
self.assertEqual(list(_normparse(u'a $ b')), [u'a $ b'])
|
||||
|
|
@ -169,13 +166,13 @@ class ParseTest(unittest.TestCase):
|
|||
self.assertEqual(list(_normexpr(parts[0].args[1])), [u'baz'])
|
||||
|
||||
def test_call_with_escaped_sep(self):
|
||||
parts = list(_normparse(u'%foo{bar,,baz}'))
|
||||
parts = list(_normparse(u'%foo{bar$,baz}'))
|
||||
self.assertEqual(len(parts), 1)
|
||||
self._assert_call(parts[0], u"foo", 1)
|
||||
self.assertEqual(list(_normexpr(parts[0].args[0])), [u'bar,baz'])
|
||||
|
||||
def test_call_with_escaped_close(self):
|
||||
parts = list(_normparse(u'%foo{bar}}baz}'))
|
||||
parts = list(_normparse(u'%foo{bar$}baz}'))
|
||||
self.assertEqual(len(parts), 1)
|
||||
self._assert_call(parts[0], u"foo", 1)
|
||||
self.assertEqual(list(_normexpr(parts[0].args[0])), [u'bar}baz'])
|
||||
|
|
@ -204,7 +201,8 @@ class ParseTest(unittest.TestCase):
|
|||
self._assert_call(parts[0], u"foo", 1)
|
||||
arg_parts = list(_normexpr(parts[0].args[0]))
|
||||
self.assertEqual(len(arg_parts), 1)
|
||||
self._assert_call(arg_parts[0], u"bar", 0)
|
||||
self._assert_call(arg_parts[0], u"bar", 1)
|
||||
self.assertEqual(list(_normexpr(arg_parts[0].args[0])), [u'baz'])
|
||||
|
||||
class EvalTest(unittest.TestCase):
|
||||
def _eval(self, template):
|
||||
|
|
|
|||
Loading…
Reference in a new issue