Commit Graph

160 Commits

Author SHA1 Message Date
Yuya Nishihara
10fda3d262 parser: shorten prefix of alias parsing errors
These messages seemed to be a bit long. We should try making them fit to
80-col console.
2016-04-17 12:31:06 +09:00
Yuya Nishihara
d21d4d0b82 ui: drop template aliases by HGPLAIN
Otherwise, scripting output could be suffered from user aliases.
2016-03-27 21:05:55 +09:00
Yuya Nishihara
ec53346d72 templater: load and expand aliases by template engine (API) (issue4842)
Now template aliases are fully supported in log and formatter templates.

As I said before, aliases are not expanded in map files. This avoids possible
corruption of our stock styles and web templates. This behavior is undocumented
since no map file nor [templates] section are documented at all. Later on,
we might want to add [aliases] section to map files if it appears to be useful.
2016-03-27 20:59:36 +09:00
Yuya Nishihara
d00a0ddedf templater: add parsing and expansion rules to process "templatealias" section
The debugtemplate command is updated to show expanded tree, but still the
template engine doesn't support alias expansion. That's why the test says
"parse error" for now.
2016-03-27 20:31:56 +09:00
FUJIWARA Katsunori
7a6d96d902 registrar: add templatefunc to mark a function as template function (API)
This patch also adds loadfunction() to templater, because this
combination helps to figure out how they cooperate with each other.

Listing up loadfunction() in dispatch.extraloaders causes implicit
loading template function at loading (3rd party) extension.

This patch explicitly tests whether templatefunc decorator works as
expected, because there is no bundled extension, which defines
template function.

This change requires that "templatefunc" attribute of (3rd party)
extension is registrar.templatefunc or so.
2016-03-30 02:10:44 +09:00
Yuya Nishihara
a32c974037 templater: do not strip non-quote characters from template config
Before this patch, the first and last characters were stripped from
ui.logtemplate and template.* if they were the same. It could lead to a
strange result as quotes are optional. See the test for example.
2016-03-27 17:42:19 +09:00
Yuya Nishihara
f0125a308f templater: do not abuse SyntaxError to report errors in template map file
SyntaxError is the class representing syntax errors in Python code. We should
use a dedicated exception class for our needs. With this change, unnecessary
re-wrapping of SyntaxError can be eliminated.
2016-03-26 18:01:04 +09:00
Yuya Nishihara
7d5bdcf68d templater: add debugtemplate command
This is useful for debugging template parsing. Several tests are ported to
this command.
2016-02-14 01:06:12 +09:00
Yuya Nishihara
633de11fa7 templater: relax type of mapped template
Now compiled template fragments are packed into a generic type, (func, data),
a string can be a valid template. This change allows us to unwrap a trivial
string node. See the next patch for details.
2016-02-14 15:42:49 +09:00
Yuya Nishihara
b20edef8a1 templater: move label() function from color extension
ui.label() is no-op by default, so we can just call ui.label() by label()
template function no matter if the color is enabled or not.
2015-06-11 23:04:14 +09:00
Yuya Nishihara
e7ec9f2344 templater: make label() take unknown symbol as color literal
Instead of the mapping hack introduced by d4686e0c15c9, this patch changes the
way how a label symbol is evaluated. This is still hackish, but should be more
predictable in that it doesn't depend on the known color effects.

This change is intended to eliminate the reference to color._effects so that
color.templatelabel() can be merged with templater.label().
2015-06-11 22:58:27 +09:00
Yuya Nishihara
e7f2a2e46a templater: handle exception when applying map operator to non-iterable object
Before this, "{noniterable % template}" raised an exception. This tries to
provide a better indication for the common case, where a left-hand-side
expression is a keyword.
2016-02-14 13:58:46 +09:00
Yuya Nishihara
40ff3175fd templater: fix shortest() to evaluate int argument and handle error 2016-02-14 13:09:17 +09:00
Yuya Nishihara
7bcf850662 templater: fix pad() to evaluate int argument and handle error 2016-02-14 13:05:09 +09:00
Yuya Nishihara
608ccd9ef6 templater: drop redundant type conversion when evaluating integer argument
A function argument may be an integer. In this case, it isn't necessary to
convert a value to string and back to integer.

Because an argument may be an arbitrary object (e.g. date tuple), TypeError
should be caught as well.
2016-02-14 12:48:14 +09:00
Yuya Nishihara
946f6161fa templater: fix revset() to evaluate format arguments eagerly
See the previous patch for why. This patch also removes redundant list()
construction from a list.
2016-02-14 00:27:09 +09:00
Yuya Nishihara
f96cf1c058 templater: fix ifcontains() to evaluate items argument eagerly
See the previous patch for why. An "items" argument may be a string,
a generator, or an arbitrary container object.
2016-02-14 00:18:12 +09:00
Yuya Nishihara
85d9fe1400 templater: fix get() to evaluate arguments eagerly
If a key is constructed from a template expression, it may be a generator.
In that case, a key have to be stringified.

A dictarg should never be a generator, but this patch also changes it to
call evalfuncarg() for consistency.
2016-02-14 00:05:58 +09:00
Yuya Nishihara
d1e05b5ef3 templatekw: switch ctx of list expression to rev of {parents} (BC)
This is the same semantics as revset() introduced at eef3c19484ca. Before
this patch, {parents} provided nothing useful in new-style template. For
example, '{parents % "{parent}"}' generated cryptic string like
"rev12345node0123abcdef...".

This patch drops {parent} variable since it was useless. We can get a revision
number by '{parents % "{rev}"}'.
2016-02-12 19:16:09 +09:00
Yuya Nishihara
5a1fcf8c16 templatekw: workaround for utf-8 round-trip of {desc}
Though our encoding strategy is best effort, {desc} is a primitive keyword
that should be worth enough to try hard to preserve UTF-8 bytes.
2015-12-27 20:21:37 +09:00
Yuya Nishihara
2e33bbee20 templatefilters: make json filter be byte-transparent (BC) (issue4926)
This is necessary to preserve filename encoding over JSON. Instead, this
patch inserts "|utf8" where non-ascii local-encoding texts can be passed
to "|json".

See also the commit that introduced "utf8" filter.
2015-12-27 17:59:57 +09:00
Yuya Nishihara
5236f2a921 templatefilters: add "utf8" to get utf-8 bytes from local-encoding text
This will be applied prior to "|json" filter. This sounds like odd, but it
is necessary to handle local-encoding text as well as raw filename bytes.

Because filenames are bytes in Mercurial and Unix world, {filename|json} should
preserve the original byte sequence, which implies

  {x|json} -> '"' toutf8b(x) '"'

On the other hand, most template strings are in local encoding. Because
"|json" filter have to be byte-transparent to filenames, we need something to
annotate an input as a local string, that's what "|utf8" will do.

  {x|utf8|json} -> '"' toutf8b(fromlocal(x)) '"'

"|utf8" is an explicit call, so aborts if input bytes can't be converted to
UTF-8.
2015-12-27 17:45:05 +09:00
Yuya Nishihara
b9ea9debff templater: evaluate each item of revset() as integer revision
Because templater.revset() returns a list of strings, repo["-1"] was mapped to
the tipmost revision. Ideally, we should make revset() return a list of integer
revisions, but it turned out not simple. If revset() is a list of integers,
"{ifcontains(rev, revset(), ...)}" would fail because "ifcontains" casts "rev"
to a string.

So this patch just converts a string back to an integer revision.
2016-02-12 18:08:53 +09:00
FUJIWARA Katsunori
b8262ddfcc tests: remove protected file forcibly for portability
Before this patch, test-command-template.t is timed out on Solaris,
because "rm" on permission denied file implies prompting "override
protection 0 (yes/no)?" and blocks execution of test script.
2016-02-05 22:32:05 +09:00
Yuya Nishihara
1f60c51fa5 templater: abort if infinite recursion detected while compiling
In this case, a template is parsed recursively with no thunk for lazy
evaluation. This patch prevents recursion by putting a dummy of the same name
into a cache that will be referenced while parsing if there's a recursion.

  changeset = {files % changeset}\n
                       ~~~~~~~~~
                        = [(_runrecursivesymbol, 'changeset')]
2015-07-23 23:41:29 +09:00
Yuya Nishihara
554208ae8f templater: abort if infinite recursion detected while evaluation (issue4758)
It would be nice if we could detect recursion at the parsing phase, but we
can't because a template can refer to a keyword of the same name. For example,
"rev = {rev}" is valid if rev is a keyword, and we don't know if rev is a
keyword or a template while parsing.
2015-07-22 23:29:41 +09:00
Yuya Nishihara
c998aff68a templatekw: add {namespaces} keyword
This provides a general-purpose interface to all custom namespaces.

The {namespaces} keyword honors the definition order of namespaces as they
are kept by sortdict.
2016-01-12 23:56:48 +09:00
Yuya Nishihara
dda890d7ab templatefilters: try round-trip utf-8 conversion by json filter (issue4933)
As JSON string is known to be a unicode, we should try round-trip conversion
for localstr type. This patch tests localstr type explicitly because
encoding.fromlocal() may raise Abort for undecodable str, which is probably
not what we want. Maybe we can refactor json filter to use encoding module
more later.

Still "{desc|json}" can't round-trip because showdescription() modifies a
localstr object.
2015-11-04 23:48:15 +09:00
Matt Mackall
86f1841884 merge with stable 2015-10-07 13:44:48 -05:00
Matt Harbison
16d4ee35c6 templater: protect word() from crashing on out of range negative value
The function isn't documented to work with negative values at all, but it does,
which can be useful.  However, the range check didn't account for this.
2015-10-05 12:37:26 -04:00
Matt Harbison
06f8907a59 templatekw: add {changes}, {distance} and {tag} to the {latesttag} keyword 2015-08-24 23:30:17 -04:00
Matt Harbison
99689724c6 templater: introduce {latesttag()} function to match a pattern (issue4184)
This allows the latest class of tag to be found, such as a release candidate or
final build, instead of just the absolute latest.

It doesn't appear that the existing keyword can be given an optional argument.
There is a keyword, function and filter for 'date', so it doesn't seem harmful
to introduce a new function with the same name as an existing keyword.  Most
functions are pretty Mercurial agnostic, but there is {revset()} as precedent.

Even though templatekw.getlatesttags() returns a single tuple, one entry of
which is a list, it is simplest to present this as a list of tags instead of a
single item, with each tag having a distance and change count attribute.  It is
also closer to how {latesttag} returns a list of tags, and how this function
works when not given a '%' operator.
2015-08-23 23:44:58 -04:00
Yuya Nishihara
80896f8bec templater: switch ctx of list expression to rev of revset() (BC)
Because revset() function generates a list of revisions, it seems sensible
to switch the ctx as well where a list expression will be evaluated. I think
"{revset(...) % "..."}" expression wasn't considered well when it was
introduced at 45e0e191755f.
2015-09-12 00:21:41 +09:00
Matt Mackall
5b498724ca templater: add new docheader/footer components for XML (issue4135)
The existing header/footer components were templated per-changeset,
and thus couldn't be correctly printed for an empty log
2015-08-26 16:27:14 -05:00
Matt Mackall
b57f682965 templater: create string unescape helper (issue4798)
This gives us a unified place to do error-handling of string-escaping
syntax errors
2015-09-09 14:43:45 -07:00
Yuya Nishihara
b81b754fe6 templater: catch regexp error at sub() function
This patch splits re.sub() into re.compile() and sub() so that it can
distinguish which argument causes re.error.
2015-09-07 21:58:17 +09:00
Yuya Nishihara
606d99d1eb templater: add optional timezone argument to localdate()
The keyword extension uses "utcdate" for a different function, so we can't
add new "utcdate" filter or function. Instead, this patch extends "localdate"
to a general timezone converter.
2015-08-18 22:15:46 +09:00
Yuya Nishihara
246636f6db templater: port localdate filter to a function
It will be extended to accept a timezone argument.
2015-09-01 19:15:16 +09:00
Danek Duvall
ccade6afcc tests: work around differing hunk headers between GNU and Solaris diff
The hunk headers specifying what lines the hunk apply to differ.  They're
irrelevant to the test, so just eliminate them from the output.
2015-07-20 15:39:15 -07:00
Danek Duvall
6c0991c070 tests: use egrep with regular expression branches for compatibility
GNU grep allows you to use "a\|b" in a regular expression to match either
"a" or "b", but at least Solaris grep does not; only egrep allows for that.
And egrep considers "a+" to be "a{1,}" instead of an "a" and a literal plus
sign, so escape that as well.
2015-07-20 15:33:20 -07:00
Yuya Nishihara
4377cc9e4b templatefilters: remove redundant 'date' and 'strip' filters
These filters are defined as 'date()' and 'strip()' functions. Help messages
are moved to the corresponding functions.
2015-07-04 16:07:42 +09:00
Yuya Nishihara
cb4039a392 templater: introduce unified filter syntax for unary functions
"filter(expr)" is allowed already. This patch adds the opposite, "expr|func".
2015-07-04 16:03:36 +09:00
Yuya Nishihara
4444465461 templater: introduce one-pass parsing of nested template strings
Instead of re-parsing quoted strings as templates, the tokenizer can delegate
the parsing of nested template strings to the parser. It has two benefits:

 1. syntax errors can be reported with absolute positions
 2. nested template can use quotes just like shell: "{"{rev}"}"

It doesn't sound nice that the tokenizer recurses into the parser. We could
instead make the tokenize itself recursive, but it would be much more
complicated because we would have to adjust binding strengths carefully and
put dummy infix operators to concatenate template fragments.

Now "string" token without r"" never appears. It will be removed by the next
patch.
2015-06-15 23:11:35 +09:00
Yuya Nishihara
c95926ebb3 templater: check existence of closing brace of template string 2015-06-15 23:03:30 +09:00
Yuya Nishihara
0cf602f409 changeset_printer: display wdirrev/wdirnode values for workingctx
Because we want to eliminate "if"s in the default template, it makes sense to
display wdirrev/wdirnode values for now. wdir() is still experimental, so the
output of "log -r'wdir()'" may change in future.
2015-07-04 17:19:49 +09:00
Yuya Nishihara
2f4ec7df91 templatekw: make {rev} return wdirrev instead of None
wdirrev/wdirnode identifiers are still experimental, but {node} is mapped to
wdirnode. So {rev} should do the same for consistency.

I'm not sure if templatekw can import scmutil. If not, we should move intrev()
to node module.
2015-07-02 22:18:21 +09:00
Yuya Nishihara
950db6aab2 templatekw: apply manifest template only if ctx.manifestnode() exists
This will prevent crash by "hg log -r 'wdir()' -Tdefault". We could use the
pseudo ff... hash introduced by 187c3ec3d83f, but it isn't proven idea yet.
For now, I want to make "hg log" just works in order to test 'wdir()' revset.

Note that unlike its name, "{manifest}" is not a list of files in that
revision, but a pair of (manifestrev, manifestnode).
2015-03-14 17:58:18 +09:00
Yuya Nishihara
2dde4312da templater: remove workaround for escaped quoted string in quoted template
This patch backs out 297d563e92af which should no longer be needed.

The test for '{\"invalid\"}' is removed because the parser is permissive for
\"...\" literal.
2015-06-27 15:28:46 +09:00
Matt Mackall
b050378961 merge with stable 2015-07-01 16:33:31 -05:00
Yuya Nishihara
274728564b templater: parse \"...\" as string for 2.9.2-3.4 compatibility (issue4733)
As of Mercurial 3.4, there were several syntax rules to process nested
template strings. Unfortunately, they were inconsistent and conflicted
each other.

 a. buildmap() rule
    - template string is _parsed_ as string, and parsed as template
    - <\"> is not allowed in nested template:
      {xs % "{f(\"{x}\")}"} -> parse error
    - template escaping <\{> is handled consistently:
      {xs % "\{x}"} -> escaped
 b. _evalifliteral() rule
    - template string is _interpreted_ as string, and parsed as template
      in crafted environment to avoid double processing of escape sequences
    - <\"> is allowed in nested template:
      {if(x, "{f(\"{x}\")}")}
    - <\{> and escape sequences in string literal in nested template are not
      handled well
 c. pad() rule
    - template string is first interpreted as string, and parsed as template,
      which means escape sequences are processed twice
    - <\"> is allowed in nested template:
      {pad("{xs % \"{x}\"}', 10)}

Because of the issue of template escaping, issue4714, 56e0b66a4c27 (in stable)
unified the rule (b) to (a). Then, 41e044cfb1ef (in default) unified the rule
(c) to (b) = (a). But they disabled the following syntax that was somewhat
considered valid.

  {if(rev, "{if(rev, \"{rev}\")}")}
  {pad("{files % \"{file}\"}", 10)}

So, this patch introduces \"...\" literal to work around the escaped-quoted
nested template strings. Because this parsing rule exists only for the backward
compatibility, it is designed to copy the behavior of old _evalifliteral() as
possible.

Future patches will introduce a better parsing rule similar to a command
substitution of POSIX shells or a string interpolation of Ruby, where extra
escapes won't be necessary at all.

  {pad("{files % "{file}"}", 10)}
        ~~~~~~~~~~~~~~~~~~
        parsed as a template, not as a string

Because <\> character wasn't allowed in a template fragment, this patch won't
introduce more breakages. But the syntax of nested templates are interpreted
differently by people, there might be unknown issues. So if we want, we could
instead remove e926f2ef639a, 72be08a15d8d and 56e0b66a4c27 from the stable
branch as the bug fixed by these patches existed for longer periods.

554d6fcc3c8, "strip single backslash before quotation mark in quoted template",
should be superseded by this patch. I'll remove it later.
2015-06-25 22:07:38 +09:00