537 return ('string', ''.join(l)) |
537 return ('string', ''.join(l)) |
538 else: |
538 else: |
539 return tuple(foldconcat(t) for t in tree) |
539 return tuple(foldconcat(t) for t in tree) |
540 |
540 |
541 def parse(spec, lookup=None): |
541 def parse(spec, lookup=None): |
542 return _parsewith(spec, lookup=lookup) |
542 try: |
|
543 return _parsewith(spec, lookup=lookup) |
|
544 except error.ParseError as inst: |
|
545 if len(inst.args) > 1: # has location |
|
546 # Add 1 to location because unlike templates, revset parse errors |
|
547 # point to the char where the error happened, not the char after. |
|
548 loc = inst.args[1] + 1 |
|
549 # Remove newlines -- spaces are equivalent whitespace. |
|
550 spec = spec.replace('\n', ' ') |
|
551 # We want the caret to point to the place in the template that |
|
552 # failed to parse, but in a hint we get a open paren at the |
|
553 # start. Therefore, we print "loc + 1" spaces (instead of "loc") |
|
554 # to line up the caret with the location of the error. |
|
555 inst.hint = spec + '\n' + ' ' * loc + '^ ' + _('here') |
|
556 raise |
543 |
557 |
544 def _quote(s): |
558 def _quote(s): |
545 r"""Quote a value in order to make it safe for the revset engine. |
559 r"""Quote a value in order to make it safe for the revset engine. |
546 |
560 |
547 >>> _quote(b'asdf') |
561 >>> _quote(b'asdf') |