mercurial/templater.py
changeset 25785 f976b7dc5e7b
parent 25784 33e613687dab
child 25800 f8f7ae0f4d98
equal deleted inserted replaced
25784:33e613687dab 25785:f976b7dc5e7b
    20     "|": (5, None, ("|", 5)),
    20     "|": (5, None, ("|", 5)),
    21     "%": (6, None, ("%", 6)),
    21     "%": (6, None, ("%", 6)),
    22     ")": (0, None, None),
    22     ")": (0, None, None),
    23     "integer": (0, ("integer",), None),
    23     "integer": (0, ("integer",), None),
    24     "symbol": (0, ("symbol",), None),
    24     "symbol": (0, ("symbol",), None),
    25     "rawstring": (0, ("rawstring",), None),
    25     "string": (0, ("string",), None),
    26     "template": (0, ("template",), None),
    26     "template": (0, ("template",), None),
    27     "end": (0, None, None),
    27     "end": (0, None, None),
    28 }
    28 }
    29 
    29 
    30 def tokenize(program, start, end):
    30 def tokenize(program, start, end):
    48                 d = program[pos]
    48                 d = program[pos]
    49                 if d == '\\': # skip over escaped characters
    49                 if d == '\\': # skip over escaped characters
    50                     pos += 2
    50                     pos += 2
    51                     continue
    51                     continue
    52                 if d == c:
    52                 if d == c:
    53                     yield ('rawstring', program[s:pos], s)
    53                     yield ('string', program[s:pos], s)
    54                     break
    54                     break
    55                 pos += 1
    55                 pos += 1
    56             else:
    56             else:
    57                 raise error.ParseError(_("unterminated string"), s)
    57                 raise error.ParseError(_("unterminated string"), s)
    58         elif c.isdigit() or c == '-':
    58         elif c.isdigit() or c == '-':
    81             # {f("\\\\ {g(\"\\\"\")}"}    \\ {g("\"")}    [r'\\', {g("\"")}]
    81             # {f("\\\\ {g(\"\\\"\")}"}    \\ {g("\"")}    [r'\\', {g("\"")}]
    82             #             ~~~~~~~~
    82             #             ~~~~~~~~
    83             #             escaped quoted string
    83             #             escaped quoted string
    84             if c == 'r':
    84             if c == 'r':
    85                 pos += 1
    85                 pos += 1
    86                 token = 'rawstring'
    86                 token = 'string'
    87             else:
    87             else:
    88                 token = 'template'
    88                 token = 'template'
    89             quote = program[pos:pos + 2]
    89             quote = program[pos:pos + 2]
    90             s = pos = pos + 2
    90             s = pos = pos + 2
    91             while pos < end: # find closing escaped quote
    91             while pos < end: # find closing escaped quote
   134     >>> _parsetemplate('foo"{bar}', 0, 9, quote='"')
   134     >>> _parsetemplate('foo"{bar}', 0, 9, quote='"')
   135     ([('string', 'foo')], 4)
   135     ([('string', 'foo')], 4)
   136     >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"')
   136     >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"')
   137     ([('string', 'foo"'), ('string', 'bar')], 9)
   137     ([('string', 'foo"'), ('string', 'bar')], 9)
   138     >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"')
   138     >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"')
   139     ([('string', 'foo\\\\')], 6)
   139     ([('string', 'foo\\')], 6)
   140     """
   140     """
   141     parsed = []
   141     parsed = []
   142     sepchars = '{' + quote
   142     sepchars = '{' + quote
   143     pos = start
   143     pos = start
   144     p = parser.parser(elements)
   144     p = parser.parser(elements)
   145     while pos < stop:
   145     while pos < stop:
   146         n = min((tmpl.find(c, pos, stop) for c in sepchars),
   146         n = min((tmpl.find(c, pos, stop) for c in sepchars),
   147                 key=lambda n: (n < 0, n))
   147                 key=lambda n: (n < 0, n))
   148         if n < 0:
   148         if n < 0:
   149             parsed.append(('string', tmpl[pos:stop]))
   149             parsed.append(('string', tmpl[pos:stop].decode('string-escape')))
   150             pos = stop
   150             pos = stop
   151             break
   151             break
   152         c = tmpl[n]
   152         c = tmpl[n]
   153         bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
   153         bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
   154         if bs % 2 == 1:
   154         if bs % 2 == 1:
   155             # escaped (e.g. '\{', '\\\{', but not '\\{')
   155             # escaped (e.g. '\{', '\\\{', but not '\\{')
   156             parsed.append(('string', (tmpl[pos:n - 1] + c)))
   156             parsed.append(('string',
       
   157                            tmpl[pos:n - 1].decode('string-escape') + c))
   157             pos = n + 1
   158             pos = n + 1
   158             continue
   159             continue
   159         if n > pos:
   160         if n > pos:
   160             parsed.append(('string', tmpl[pos:n]))
   161             parsed.append(('string', tmpl[pos:n].decode('string-escape')))
   161         if c == quote:
   162         if c == quote:
   162             return parsed, n + 1
   163             return parsed, n + 1
   163 
   164 
   164         parseres, pos = p.parse(tokenize(tmpl, n + 1, stop))
   165         parseres, pos = p.parse(tokenize(tmpl, n + 1, stop))
   165         parsed.append(parseres)
   166         parsed.append(parseres)
   210 
   211 
   211 def runinteger(context, mapping, data):
   212 def runinteger(context, mapping, data):
   212     return int(data)
   213     return int(data)
   213 
   214 
   214 def runstring(context, mapping, data):
   215 def runstring(context, mapping, data):
   215     return data.decode("string-escape")
       
   216 
       
   217 def runrawstring(context, mapping, data):
       
   218     return data
   216     return data
   219 
   217 
   220 def runsymbol(context, mapping, key):
   218 def runsymbol(context, mapping, key):
   221     v = mapping.get(key)
   219     v = mapping.get(key)
   222     if v is None:
   220     if v is None:
   657 
   655 
   658 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
   656 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
   659 exprmethods = {
   657 exprmethods = {
   660     "integer": lambda e, c: (runinteger, e[1]),
   658     "integer": lambda e, c: (runinteger, e[1]),
   661     "string": lambda e, c: (runstring, e[1]),
   659     "string": lambda e, c: (runstring, e[1]),
   662     "rawstring": lambda e, c: (runrawstring, e[1]),
       
   663     "symbol": lambda e, c: (runsymbol, e[1]),
   660     "symbol": lambda e, c: (runsymbol, e[1]),
   664     "template": buildtemplate,
   661     "template": buildtemplate,
   665     "group": lambda e, c: compileexp(e[1], c, exprmethods),
   662     "group": lambda e, c: compileexp(e[1], c, exprmethods),
   666 #    ".": buildmember,
   663 #    ".": buildmember,
   667     "|": buildfilter,
   664     "|": buildfilter,