664 >>> formatspec(b'sort(%r, %ps)', b':', [b'desc', b'user']) |
664 >>> formatspec(b'sort(%r, %ps)', b':', [b'desc', b'user']) |
665 "sort((:), 'desc', 'user')" |
665 "sort((:), 'desc', 'user')" |
666 >>> formatspec(b'%ls', [b'a', b"'"]) |
666 >>> formatspec(b'%ls', [b'a', b"'"]) |
667 "_list('a\\\\x00\\\\'')" |
667 "_list('a\\\\x00\\\\'')" |
668 ''' |
668 ''' |
|
669 parsed = _parseargs(expr, args) |
|
670 ret = [] |
|
671 for t, arg in parsed: |
|
672 if t is None: |
|
673 ret.append(arg) |
|
674 else: |
|
675 raise error.ProgrammingError("unknown revspec item type: %r" % t) |
|
676 return b''.join(ret) |
|
677 |
|
678 def _parseargs(expr, args): |
|
679 """parse the expression and replace all inexpensive args |
|
680 |
|
681 return a list of tuple [(arg-type, arg-value)] |
|
682 |
|
683 Arg-type can be: |
|
684 * None: a string ready to be concatenated into a final spec |
|
685 """ |
669 expr = pycompat.bytestr(expr) |
686 expr = pycompat.bytestr(expr) |
670 argiter = iter(args) |
687 argiter = iter(args) |
671 ret = [] |
688 ret = [] |
672 pos = 0 |
689 pos = 0 |
673 while pos < len(expr): |
690 while pos < len(expr): |
674 q = expr.find('%', pos) |
691 q = expr.find('%', pos) |
675 if q < 0: |
692 if q < 0: |
676 ret.append(expr[pos:]) |
693 ret.append((None, expr[pos:])) |
677 break |
694 break |
678 ret.append(expr[pos:q]) |
695 ret.append((None, expr[pos:q])) |
679 pos = q + 1 |
696 pos = q + 1 |
680 try: |
697 try: |
681 d = expr[pos] |
698 d = expr[pos] |
682 except IndexError: |
699 except IndexError: |
683 raise error.ParseError(_('incomplete revspec format character')) |
700 raise error.ParseError(_('incomplete revspec format character')) |
684 if d == '%': |
701 if d == '%': |
685 ret.append(d) |
702 ret.append((None, d)) |
686 pos += 1 |
703 pos += 1 |
687 continue |
704 continue |
688 |
705 |
689 try: |
706 try: |
690 arg = next(argiter) |
707 arg = next(argiter) |
691 except StopIteration: |
708 except StopIteration: |
692 raise error.ParseError(_('missing argument for revspec')) |
709 raise error.ParseError(_('missing argument for revspec')) |
693 f = _formatlistfuncs.get(d) |
710 f = _formatlistfuncs.get(d) |
694 if f: |
711 if f: |
695 # a list of some type |
712 # a list of some type, might be expensive, do not replace |
696 pos += 1 |
713 pos += 1 |
697 try: |
714 try: |
698 d = expr[pos] |
715 d = expr[pos] |
699 except IndexError: |
716 except IndexError: |
700 raise error.ParseError(_('incomplete revspec format character')) |
717 raise error.ParseError(_('incomplete revspec format character')) |
701 try: |
718 try: |
702 ret.append(f(list(arg), d)) |
719 ret.append((None, f(list(arg), d))) |
703 except (TypeError, ValueError): |
720 except (TypeError, ValueError): |
704 raise error.ParseError(_('invalid argument for revspec')) |
721 raise error.ParseError(_('invalid argument for revspec')) |
705 else: |
722 else: |
|
723 # a single entry, not expensive, replace |
706 try: |
724 try: |
707 ret.append(_formatargtype(d, arg)) |
725 ret.append((None, _formatargtype(d, arg))) |
708 except (TypeError, ValueError): |
726 except (TypeError, ValueError): |
709 raise error.ParseError(_('invalid argument for revspec')) |
727 raise error.ParseError(_('invalid argument for revspec')) |
710 pos += 1 |
728 pos += 1 |
711 |
729 |
712 try: |
730 try: |
713 next(argiter) |
731 next(argiter) |
714 raise error.ParseError(_('too many revspec arguments specified')) |
732 raise error.ParseError(_('too many revspec arguments specified')) |
715 except StopIteration: |
733 except StopIteration: |
716 pass |
734 pass |
717 return ''.join(ret) |
735 return ret |
718 |
736 |
719 def prettyformat(tree): |
737 def prettyformat(tree): |
720 return parser.prettyformat(tree, ('string', 'symbol')) |
738 return parser.prettyformat(tree, ('string', 'symbol')) |
721 |
739 |
722 def depth(tree): |
740 def depth(tree): |