# HG changeset patch # User FUJIWARA Katsunori # Date 1459271444 -32400 # Node ID efa192203623a7033fc2ed75750c21eb608d29cb # Parent cc103bd0dbf9617608d36b878f9efd78addeb714 templater: use templatefunc to mark a function as template function Using decorator can localize changes for adding (or removing) a template function in source code. This patch also removes leading ":FUNC(ARG...):" part in help document of each function, because using templatefunc makes it useless. This patch uses not 'func' but 'templatefunc' as a decorator name, because the former is too generic one, even though the latter is a little redundant in 'templater.py'. diff -r cc103bd0dbf9 -r efa192203623 mercurial/templater.py --- a/mercurial/templater.py Wed Mar 30 02:10:44 2016 +0900 +++ b/mercurial/templater.py Wed Mar 30 02:10:44 2016 +0900 @@ -17,6 +17,7 @@ error, minirst, parser, + registrar, revset as revsetmod, templatefilters, templatekw, @@ -393,8 +394,14 @@ return (runfilter, (args[0], f)) raise error.ParseError(_("unknown function '%s'") % n) +# dict of template built-in functions +funcs = {} + +templatefunc = registrar.templatefunc(funcs) + +@templatefunc('date(date[, fmt])') def date(context, mapping, args): - """:date(date[, fmt]): Format a date. See :hg:`help dates` for formatting + """Format a date. See :hg:`help dates` for formatting strings. The default is a Unix date format, including the timezone: "Mon Sep 04 15:13:13 2006 0700".""" if not (1 <= len(args) <= 2): @@ -414,8 +421,9 @@ # i18n: "date" is a keyword raise error.ParseError(_("date expects a date information")) +@templatefunc('diff([includepattern [, excludepattern]])') def diff(context, mapping, args): - """:diff([includepattern [, excludepattern]]): Show a diff, optionally + """Show a diff, optionally specifying files to include or exclude.""" if len(args) > 2: # i18n: "diff" is a keyword @@ -433,8 +441,9 @@ return ''.join(chunks) +@templatefunc('fill(text[, width[, initialident[, hangindent]]])') def fill(context, mapping, args): - """:fill(text[, width[, initialident[, hangindent]]]): Fill many + """Fill many paragraphs with optional indentation. See the "fill" filter.""" if not (1 <= len(args) <= 4): # i18n: "fill" is a keyword @@ -456,8 +465,9 @@ return templatefilters.fill(text, width, initindent, hangindent) +@templatefunc('pad(text, width[, fillchar=\' \'[, right=False]])') def pad(context, mapping, args): - """:pad(text, width[, fillchar=' '[, right=False]]): Pad text with a + """Pad text with a fill character.""" if not (2 <= len(args) <= 4): # i18n: "pad" is a keyword @@ -481,8 +491,9 @@ else: return text.ljust(width, fillchar) +@templatefunc('indent(text, indentchars[, firstline])') def indent(context, mapping, args): - """:indent(text, indentchars[, firstline]): Indents all non-empty lines + """Indents all non-empty lines with the characters given in the indentchars string. An optional third parameter will override the indent for the first line only if present.""" @@ -501,8 +512,9 @@ # the indent function doesn't indent the first line, so we do it here return templatefilters.indent(firstline + text, indent) +@templatefunc('get(dict, key)') def get(context, mapping, args): - """:get(dict, key): Get an attribute/key from an object. Some keywords + """Get an attribute/key from an object. Some keywords are complex types. This function allows you to obtain the value of an attribute on these types.""" if len(args) != 2: @@ -517,8 +529,9 @@ key = evalfuncarg(context, mapping, args[1]) return dictarg.get(key) +@templatefunc('if(expr, then[, else])') def if_(context, mapping, args): - """:if(expr, then[, else]): Conditionally execute based on the result of + """Conditionally execute based on the result of an expression.""" if not (2 <= len(args) <= 3): # i18n: "if" is a keyword @@ -530,8 +543,9 @@ elif len(args) == 3: yield args[2][0](context, mapping, args[2][1]) +@templatefunc('ifcontains(search, thing, then[, else])') def ifcontains(context, mapping, args): - """:ifcontains(search, thing, then[, else]): Conditionally execute based + """Conditionally execute based on whether the item "search" is in "thing".""" if not (3 <= len(args) <= 4): # i18n: "ifcontains" is a keyword @@ -545,8 +559,9 @@ elif len(args) == 4: yield args[3][0](context, mapping, args[3][1]) +@templatefunc('ifeq(expr1, expr2, then[, else])') def ifeq(context, mapping, args): - """:ifeq(expr1, expr2, then[, else]): Conditionally execute based on + """Conditionally execute based on whether 2 items are equivalent.""" if not (3 <= len(args) <= 4): # i18n: "ifeq" is a keyword @@ -559,8 +574,9 @@ elif len(args) == 4: yield args[3][0](context, mapping, args[3][1]) +@templatefunc('join(list, sep)') def join(context, mapping, args): - """:join(list, sep): Join items in a list with a delimiter.""" + """Join items in a list with a delimiter.""" if not (1 <= len(args) <= 2): # i18n: "join" is a keyword raise error.ParseError(_("join expects one or two arguments")) @@ -582,8 +598,9 @@ yield joiner yield x +@templatefunc('label(label, expr)') def label(context, mapping, args): - """:label(label, expr): Apply a label to generated content. Content with + """Apply a label to generated content. Content with a label applied can result in additional post-processing, such as automatic colorization.""" if len(args) != 2: @@ -598,8 +615,9 @@ return ui.label(thing, label) +@templatefunc('latesttag([pattern])') def latesttag(context, mapping, args): - """:latesttag([pattern]): The global tags matching the given pattern on the + """The global tags matching the given pattern on the most recent globally tagged ancestor of this changeset.""" if len(args) > 1: # i18n: "latesttag" is a keyword @@ -611,8 +629,9 @@ return templatekw.showlatesttags(pattern, **mapping) +@templatefunc('localdate(date[, tz])') def localdate(context, mapping, args): - """:localdate(date[, tz]): Converts a date to the specified timezone. + """Converts a date to the specified timezone. The default is local date.""" if not (1 <= len(args) <= 2): # i18n: "localdate" is a keyword @@ -639,8 +658,9 @@ tzoffset = util.makedate()[1] return (date[0], tzoffset) +@templatefunc('revset(query[, formatargs...])') def revset(context, mapping, args): - """:revset(query[, formatargs...]): Execute a revision set query. See + """Execute a revision set query. See :hg:`help revset`.""" if not len(args) > 0: # i18n: "revset" is a keyword @@ -669,8 +689,9 @@ return templatekw.showrevslist("revision", revs, **mapping) +@templatefunc('rstdoc(text, style)') def rstdoc(context, mapping, args): - """:rstdoc(text, style): Format ReStructuredText.""" + """Format ReStructuredText.""" if len(args) != 2: # i18n: "rstdoc" is a keyword raise error.ParseError(_("rstdoc expects two arguments")) @@ -680,8 +701,9 @@ return minirst.format(text, style=style, keep=['verbose']) +@templatefunc('shortest(node, minlength=4)') def shortest(context, mapping, args): - """:shortest(node, minlength=4): Obtain the shortest representation of + """Obtain the shortest representation of a node.""" if not (1 <= len(args) <= 2): # i18n: "shortest" is a keyword @@ -734,8 +756,9 @@ if len(shortest) <= length: return shortest +@templatefunc('strip(text[, chars])') def strip(context, mapping, args): - """:strip(text[, chars]): Strip characters from a string. By default, + """Strip characters from a string. By default, strips all leading and trailing whitespace.""" if not (1 <= len(args) <= 2): # i18n: "strip" is a keyword @@ -747,8 +770,9 @@ return text.strip(chars) return text.strip() +@templatefunc('sub(pattern, replacement, expression)') def sub(context, mapping, args): - """:sub(pattern, replacement, expression): Perform text substitution + """Perform text substitution using regular expressions.""" if len(args) != 3: # i18n: "sub" is a keyword @@ -768,8 +792,9 @@ # i18n: "sub" is a keyword raise error.ParseError(_("sub got an invalid replacement: %s") % rpl) +@templatefunc('startswith(pattern, text)') def startswith(context, mapping, args): - """:startswith(pattern, text): Returns the value from the "text" argument + """Returns the value from the "text" argument if it begins with the content from the "pattern" argument.""" if len(args) != 2: # i18n: "startswith" is a keyword @@ -781,9 +806,9 @@ return text return '' - +@templatefunc('word(number, text[, separator])') def word(context, mapping, args): - """:word(number, text[, separator]): Return the nth word from a string.""" + """Return the nth word from a string.""" if not (2 <= len(args) <= 3): # i18n: "word" is a keyword raise error.ParseError(_("word expects two or three arguments, got %d") @@ -821,29 +846,6 @@ methods = exprmethods.copy() methods["integer"] = exprmethods["symbol"] # '{1}' as variable -funcs = { - "date": date, - "diff": diff, - "fill": fill, - "get": get, - "if": if_, - "ifcontains": ifcontains, - "ifeq": ifeq, - "indent": indent, - "join": join, - "label": label, - "latesttag": latesttag, - "localdate": localdate, - "pad": pad, - "revset": revset, - "rstdoc": rstdoc, - "shortest": shortest, - "startswith": startswith, - "strip": strip, - "sub": sub, - "word": word, -} - # template engine stringify = templatefilters.stringify