Commit Graph

244 Commits

Author SHA1 Message Date
Pierre-Yves David
30913031d4 error: get Abort from 'error' instead of 'util'
The home of 'Abort' is 'error' not 'util' however, a lot of code seems to be
confused about that and gives all the credit to 'util' instead of the
hardworking 'error'. In a spirit of equity, we break the cycle of injustice and
give back to 'error' the respect it deserves. And screw that 'util' poser.

For great justice.
2015-10-08 12:55:45 -07:00
Matt Mackall
3302d0eab4 merge with stable 2015-10-08 17:44:22 -05:00
Yuya Nishihara
3bbeb95ce8 templater: do not pre-evaluate generator keyword at runsymbol (issue4868)
It was introduced by 236440938a03, but the important code was removed by
fcf2407610f4. So there was no positive effect other than exhausting memory.

The problem spotted by 236440938a03 is that you can't use a generator keyword
more than once. For example, in hgweb template, "{child} {child}" doesn't work
because the first "{child}" consumes the generator. But as fcf2407610f4 says,
the fix was wrong because it could overwrite a callable keyword that returns
a generator. Also the fix didn't work for a generator of generator such as
"{diff}" keyword. So, the proper fix for that problem would be to not put
a generator in a keyword table. Instead, it should be a factory of a generator.

Note that this should fix the memory issue in hgweb, but my firefox killed by
OOM in place. Be careful to not use a modern web browser to test the issue4868.
2015-10-08 23:24:38 +09: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 Mackall
86f1841884 merge with stable 2015-10-07 13:44:48 -05: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
Pierre-Yves David
6988077eb7 templater: remove a mutable default argument
Mutable default arguments are know to the state of California to cause bugs.
2015-09-24 01:07:09 -07:00
Pierre-Yves David
031cb65d89 templater: remove a mutable default argument
Mutable default arguments are know to the state of California to cause bugs.
2015-09-24 01:06:41 -07:00
Pierre-Yves David
3ea92affd9 templater: remove a mutable default argument
Mutable default arguments are know to the state of California to cause bugs.
2015-09-24 01:06:10 -07:00
Pierre-Yves David
21ad2eebc2 templater: remove a mutable default argument
Mutable default arguments are know to the state of California to cause bugs.
2015-09-24 01:05:21 -07:00
Pierre-Yves David
9bd6d983a9 templater: remove a mutable default argument
Mutable default arguments are know to the state of California to cause bugs.
2015-09-24 01:04:58 -07: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
Yuya Nishihara
9e9d73bc11 parser: move unescape helper from templater
revset and fileset have a similar problem, so let's make it a common helper
function.
2015-09-10 23:25:10 +09: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
timeless@mozdev.org
eba11ddf67 templater: fix get English 2015-08-30 17:50:55 -04: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
Yuya Nishihara
dfa87bb62f templater: drop unneeded destructuring of argument tuple at buildfilter
Because evalfuncarg() accepts an argument tuple, there is little meaning
to pass (func, data, filt) in place of ((func, data), filt).
2015-09-01 19:04:10 +09:00
Yuya Nishihara
f54bea3c82 templater: extract helper that evaluates filter or function argument
It will be used to get a date tuple from an argument. Perhaps some of
"stringify(args[n][0], ...)" can be replaced by this function.
2015-09-01 18:57:50 +09: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
9f4d48e57c templater: inline getfilter() to buildfilter()
This prepares for the unified filter syntax that will be introduced by the
next patch.
2015-07-04 15:59:03 +09:00
Yuya Nishihara
b4caf94446 parser: separate actions for primary expression and prefix operator
This will allow us to define both a primary expression, ":", and a prefix
operator, ":y". The ambiguity will be resolved by the next patch.

Prefix actions in elements table are adjusted as follows:

  original prefix      primary  prefix
  -----------------    -------- -----------------
  ("group", 1, ")") -> n/a      ("group", 1, ")")
  ("negate", 19)    -> n/a      ("negate", 19)
  ("symbol",)       -> "symbol" n/a
2015-07-05 12:02:13 +09:00
Gregory Szorc
1e68b1d684 templater: use absolute_import 2015-08-08 18:23:53 -07:00
Yuya Nishihara
4645c24be5 parser: fill invalid infix and suffix actions by None
This can simplify the expansion of (prefix, infix, suffix) actions.
2015-07-05 11:17:22 +09:00
Yuya Nishihara
b677e35b5b parser: add comment about structure of elements to each table 2015-07-05 11:06:58 +09:00
Yuya Nishihara
14b69768fa templater: unify "string" and "rawstring"
"rawstring" was introduced by cd1b50e99ed8, but it's no longer necessary
because 4f14a9644001 and e99f4f59d2e9 changed the way of processing string
literals.

This patch moves string decoding to the parsing phase as it was before:

  ('rawstring', s) -> ('string', s)
  ('string', s) -> ('string', s.decode('string-escape'))
2015-06-20 18:24:11 +09:00
Yuya Nishihara
24dbced64e templater: remove processing of "string" literals from tokenizer
They are processed as "template" strings now.
2015-06-21 13:28:21 +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
50e76230c0 templater: extract function that parses template string
It will be called recursively to parse nested template strings.
2015-06-15 22:55:34 +09:00
Yuya Nishihara
d77b812a50 templater: respect stop position while parsing template string
It has no effect now because stop is len(tmpl).
2015-06-15 23:00:42 +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
Matt Mackall
0508027d17 merge with stable 2015-06-24 13:41:27 -05:00
Gregory Szorc
5380dea2a7 global: mass rewrite to use modern exception syntax
Python 2.6 introduced the "except type as instance" syntax, replacing
the "except type, instance" syntax that came before. Python 3 dropped
support for the latter syntax. Since we no longer support Python 2.4 or
2.5, we have no need to continue supporting the "except type, instance".

This patch mass rewrites the exception syntax to be Python 2.6+ and
Python 3 compatible.

This patch was produced by running `2to3 -f except -w -n .`.
2015-06-23 22:20:08 -07:00
Yuya Nishihara
ec7ad76871 templater: fix handling of \-escapes in raw string literals
The backslash character should start escape sequences no matter if a string is
prefixed with 'r'. They are just not interpreted as escape sequences in raw
strings. revset.tokenize() handles them correctly, but templater didn't.

https://docs.python.org/2/reference/lexical_analysis.html#string-literals
2015-06-21 13:24:43 +09:00
Yuya Nishihara
fe462ed8ac parser: accept iterator of tokens instead of tokenizer function and program
This can simplify the interface of parse() function. Our tokenizer tends to
have optional arguments other than the message to be parsed.

Before this patch, the "lookup" argument existed only for the revset, and the
templater had to pack [program, start, end] to be passed to its tokenizer.
2015-06-21 00:49:26 +09:00
Yuya Nishihara
930b78aeff templater: evaluate "query" argument passed to revset()
revset() had the same issue as f921aa09b251. It crashed by passing non-string
expression.
2015-06-20 23:13:34 +09:00
Yuya Nishihara
bd614aebda templater: evaluate arguments passed to diff() appropriately
Before this patch, diff() crashed by passing non-string expression because
it didn't evaluate arguments at all.
2015-06-13 20:14:22 +09:00
Yuya Nishihara
54bbfd7f6b templater: do not preprocess template string in "if" expression (issue4714)
The problem was spotted at cd1b50e99ed8, that says "this patch invokes it
with "strtoken='rawstring'" in "_evalifliteral()", because "t" is the result
of "arg" evaluation and it should be "string-escape"-ed if "arg" is "string"
expression." This workaround is no longer valid since 72be08a15d8d introduced
strict parsing of '\{'.

Instead, we should interpret bare token as "string" or "rawstring" template.
This is what buildmap() does at parsing phase.
2015-06-08 18:14:22 +09:00
Yuya Nishihara
60069c670b templater: strictly parse leading backslashes of '{' (issue4569) (BC)
Because double backslashes are processed as a string escape sequence, '\\{'
should start the template syntax. On the other hand, r'' disables any sort
of \-escapes, so r'\{' can go either way, never start the template syntax
or always start it. I simply chose the latter, which means r'\{' is the same
as '\\{'.
2015-05-04 10:17:34 +09:00
Yuya Nishihara
6b7d953b63 templater: do not process \-escapes at parsestring() (issue4290)
This patch brings back pre-2.8.1 behavior.

The result of parsestring() is stored in templater's cache, t.cache, and then
it is parsed as a template string by compiletemplate(). So t.cache should keep
an unparsed string no matter if it is sourced from config value. Otherwise
backslashes would be processed twice.

The test vector is borrowed from 83ff877959a6.
2015-05-04 09:54:01 +09:00
Yuya Nishihara
9420a5f503 templater: fix crash by passing invalid object to date() function
"date information" is somewhat obscure, but we call it that way in
templatekw.showdate().
2015-05-03 17:33:14 +09:00
Ryan McElroy
c2a7f23bdb templater: fail more gracefully for blank strings to word 2015-04-30 12:33:36 -07:00
Yuya Nishihara
6c27e6c97a templater: tell hggettext to collect help of template functions 2015-04-03 21:36:39 +09:00
Gregory Szorc
b6dd5a0076 templater: add consistent docstrings to functions
The content of "hg help templating" is largely derived from docstrings
on functions providing functionality. Template functions are the long
holdout.

Prepare for generating them dynamically by defining docstrings for all
template functions.

There are numerous ways these docs could be improved. Right now, the
help output simply shows function names and arguments. So literally
any accurate data is better than what is there now.
2015-04-01 20:19:43 -07:00
Yuya Nishihara
83ca04362c templater: comment that gettemplate() has different name resolution order
I've tried to unify gettemplate() with buildtemplate(), but it didn't go well
because gettemplate() have to bypass mapping dict.

For example, web templates have '{tags%changelogtag}' and 'changelogtag' is
defined in both mapping, the default, and context.cache, sourced from map file.
In general, mapping shadows context variables, but gettemplate() have to pick
it from context.cache.
2015-06-16 22:13:19 +09:00