equal
deleted
inserted
replaced
380 |
380 |
381 def _runrecursivesymbol(context, mapping, key): |
381 def _runrecursivesymbol(context, mapping, key): |
382 raise error.Abort(_("recursive reference '%s' in template") % key) |
382 raise error.Abort(_("recursive reference '%s' in template") % key) |
383 |
383 |
384 def runsymbol(context, mapping, key, default=''): |
384 def runsymbol(context, mapping, key, default=''): |
385 v = mapping.get(key) |
385 v = context.symbol(mapping, key) |
386 if v is None: |
|
387 v = context._defaults.get(key) |
|
388 if v is None: |
386 if v is None: |
389 # put poison to cut recursion. we can't move this to parsing phase |
387 # put poison to cut recursion. we can't move this to parsing phase |
390 # because "x = {x}" is allowed if "x" is a keyword. (issue4758) |
388 # because "x = {x}" is allowed if "x" is a keyword. (issue4758) |
391 safemapping = mapping.copy() |
389 safemapping = mapping.copy() |
392 safemapping[key] = _recursivesymbolblocker(key) |
390 safemapping[key] = _recursivesymbolblocker(key) |
624 s = evalstring(context, mapping, args[i]).strip() |
622 s = evalstring(context, mapping, args[i]).strip() |
625 if s: |
623 if s: |
626 return [s] |
624 return [s] |
627 return [] |
625 return [] |
628 |
626 |
629 ctx = mapping['ctx'] |
627 ctx = context.resource(mapping, 'ctx') |
630 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1))) |
628 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1))) |
631 |
629 |
632 return ''.join(chunks) |
630 return ''.join(chunks) |
633 |
631 |
634 @templatefunc('extdata(source)', argspec='source') |
632 @templatefunc('extdata(source)', argspec='source') |
637 if 'source' not in args: |
635 if 'source' not in args: |
638 # i18n: "extdata" is a keyword |
636 # i18n: "extdata" is a keyword |
639 raise error.ParseError(_('extdata expects one argument')) |
637 raise error.ParseError(_('extdata expects one argument')) |
640 |
638 |
641 source = evalstring(context, mapping, args['source']) |
639 source = evalstring(context, mapping, args['source']) |
642 cache = mapping['cache'].setdefault('extdata', {}) |
640 cache = context.resource(mapping, 'cache').setdefault('extdata', {}) |
643 ctx = mapping['ctx'] |
641 ctx = context.resource(mapping, 'ctx') |
644 if source in cache: |
642 if source in cache: |
645 data = cache[source] |
643 data = cache[source] |
646 else: |
644 else: |
647 data = cache[source] = scmutil.extdatasource(ctx.repo(), source) |
645 data = cache[source] = scmutil.extdatasource(ctx.repo(), source) |
648 return data.get(ctx.rev(), '') |
646 return data.get(ctx.rev(), '') |
654 if not len(args) == 1: |
652 if not len(args) == 1: |
655 # i18n: "files" is a keyword |
653 # i18n: "files" is a keyword |
656 raise error.ParseError(_("files expects one argument")) |
654 raise error.ParseError(_("files expects one argument")) |
657 |
655 |
658 raw = evalstring(context, mapping, args[0]) |
656 raw = evalstring(context, mapping, args[0]) |
659 ctx = mapping['ctx'] |
657 ctx = context.resource(mapping, 'ctx') |
660 m = ctx.match([raw]) |
658 m = ctx.match([raw]) |
661 files = list(ctx.matches(m)) |
659 files = list(ctx.matches(m)) |
662 return templatekw.showlist("file", files, mapping) |
660 return templatekw.showlist("file", files, mapping) |
663 |
661 |
664 @templatefunc('fill(text[, width[, initialident[, hangindent]]])') |
662 @templatefunc('fill(text[, width[, initialident[, hangindent]]])') |
690 """Obtain the preferred form of a changeset hash. (DEPRECATED)""" |
688 """Obtain the preferred form of a changeset hash. (DEPRECATED)""" |
691 if len(args) != 1: |
689 if len(args) != 1: |
692 # i18n: "formatnode" is a keyword |
690 # i18n: "formatnode" is a keyword |
693 raise error.ParseError(_("formatnode expects one argument")) |
691 raise error.ParseError(_("formatnode expects one argument")) |
694 |
692 |
695 ui = mapping['ui'] |
693 ui = context.resource(mapping, 'ui') |
696 node = evalstring(context, mapping, args[0]) |
694 node = evalstring(context, mapping, args[0]) |
697 if ui.debugflag: |
695 if ui.debugflag: |
698 return node |
696 return node |
699 return templatefilters.short(node) |
697 return templatefilters.short(node) |
700 |
698 |
856 automatic colorization.""" |
854 automatic colorization.""" |
857 if len(args) != 2: |
855 if len(args) != 2: |
858 # i18n: "label" is a keyword |
856 # i18n: "label" is a keyword |
859 raise error.ParseError(_("label expects two arguments")) |
857 raise error.ParseError(_("label expects two arguments")) |
860 |
858 |
861 ui = mapping['ui'] |
859 ui = context.resource(mapping, 'ui') |
862 thing = evalstring(context, mapping, args[1]) |
860 thing = evalstring(context, mapping, args[1]) |
863 # preserve unknown symbol as literal so effects like 'red', 'bold', |
861 # preserve unknown symbol as literal so effects like 'red', 'bold', |
864 # etc. don't need to be quoted |
862 # etc. don't need to be quoted |
865 label = evalstringliteral(context, mapping, args[0]) |
863 label = evalstringliteral(context, mapping, args[0]) |
866 |
864 |
1028 the current working directory.""" |
1026 the current working directory.""" |
1029 if len(args) != 1: |
1027 if len(args) != 1: |
1030 # i18n: "relpath" is a keyword |
1028 # i18n: "relpath" is a keyword |
1031 raise error.ParseError(_("relpath expects one argument")) |
1029 raise error.ParseError(_("relpath expects one argument")) |
1032 |
1030 |
1033 repo = mapping['ctx'].repo() |
1031 repo = context.resource(mapping, 'ctx').repo() |
1034 path = evalstring(context, mapping, args[0]) |
1032 path = evalstring(context, mapping, args[0]) |
1035 return repo.pathto(path) |
1033 return repo.pathto(path) |
1036 |
1034 |
1037 @templatefunc('revset(query[, formatargs...])') |
1035 @templatefunc('revset(query[, formatargs...])') |
1038 def revset(context, mapping, args): |
1036 def revset(context, mapping, args): |
1041 if not len(args) > 0: |
1039 if not len(args) > 0: |
1042 # i18n: "revset" is a keyword |
1040 # i18n: "revset" is a keyword |
1043 raise error.ParseError(_("revset expects one or more arguments")) |
1041 raise error.ParseError(_("revset expects one or more arguments")) |
1044 |
1042 |
1045 raw = evalstring(context, mapping, args[0]) |
1043 raw = evalstring(context, mapping, args[0]) |
1046 ctx = mapping['ctx'] |
1044 ctx = context.resource(mapping, 'ctx') |
1047 repo = ctx.repo() |
1045 repo = ctx.repo() |
1048 |
1046 |
1049 def query(expr): |
1047 def query(expr): |
1050 m = revsetmod.match(repo.ui, expr, repo=repo) |
1048 m = revsetmod.match(repo.ui, expr, repo=repo) |
1051 return m(repo) |
1049 return m(repo) |
1053 if len(args) > 1: |
1051 if len(args) > 1: |
1054 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]] |
1052 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]] |
1055 revs = query(revsetlang.formatspec(raw, *formatargs)) |
1053 revs = query(revsetlang.formatspec(raw, *formatargs)) |
1056 revs = list(revs) |
1054 revs = list(revs) |
1057 else: |
1055 else: |
1058 revsetcache = mapping['cache'].setdefault("revsetcache", {}) |
1056 cache = context.resource(mapping, 'cache') |
|
1057 revsetcache = cache.setdefault("revsetcache", {}) |
1059 if raw in revsetcache: |
1058 if raw in revsetcache: |
1060 revs = revsetcache[raw] |
1059 revs = revsetcache[raw] |
1061 else: |
1060 else: |
1062 revs = query(raw) |
1061 revs = query(raw) |
1063 revs = list(revs) |
1062 revs = list(revs) |
1114 _("shortest() expects an integer minlength")) |
1113 _("shortest() expects an integer minlength")) |
1115 |
1114 |
1116 # _partialmatch() of filtered changelog could take O(len(repo)) time, |
1115 # _partialmatch() of filtered changelog could take O(len(repo)) time, |
1117 # which would be unacceptably slow. so we look for hash collision in |
1116 # which would be unacceptably slow. so we look for hash collision in |
1118 # unfiltered space, which means some hashes may be slightly longer. |
1117 # unfiltered space, which means some hashes may be slightly longer. |
1119 cl = mapping['ctx']._repo.unfiltered().changelog |
1118 cl = context.resource(mapping, 'ctx')._repo.unfiltered().changelog |
1120 return cl.shortest(node, minlength) |
1119 return cl.shortest(node, minlength) |
1121 |
1120 |
1122 @templatefunc('strip(text[, chars])') |
1121 @templatefunc('strip(text[, chars])') |
1123 def strip(context, mapping, args): |
1122 def strip(context, mapping, args): |
1124 """Strip characters from a string. By default, |
1123 """Strip characters from a string. By default, |
1300 defaults = {} |
1299 defaults = {} |
1301 self._defaults = defaults |
1300 self._defaults = defaults |
1302 self._aliasmap = _aliasrules.buildmap(aliases) |
1301 self._aliasmap = _aliasrules.buildmap(aliases) |
1303 self._cache = {} # key: (func, data) |
1302 self._cache = {} # key: (func, data) |
1304 |
1303 |
|
1304 def symbol(self, mapping, key): |
|
1305 """Resolve symbol to value or function; None if nothing found""" |
|
1306 v = mapping.get(key) |
|
1307 if v is None: |
|
1308 v = self._defaults.get(key) |
|
1309 return v |
|
1310 |
|
1311 def resource(self, mapping, key): |
|
1312 """Return internal data (e.g. cache) used for keyword/function |
|
1313 evaluation""" |
|
1314 return mapping[key] |
|
1315 |
1305 def _load(self, t): |
1316 def _load(self, t): |
1306 '''load, parse, and cache a template''' |
1317 '''load, parse, and cache a template''' |
1307 if t not in self._cache: |
1318 if t not in self._cache: |
1308 # put poison to cut recursion while compiling 't' |
1319 # put poison to cut recursion while compiling 't' |
1309 self._cache[t] = (_runrecursivesymbol, t) |
1320 self._cache[t] = (_runrecursivesymbol, t) |