Commit Graph

191 Commits

Author SHA1 Message Date
Yuya Nishihara
75bcdb63fb formatter: load templates section like a map file
Since a map file has another level to select a template (spec -> mapfile
-> topic), this isn't exactly the same as how a map file works. But I believe
most users would expect the new behavior.

A literal template is stored as an unnamed template so that it will never
conflict with the templates defined in [templates] section.
2017-04-22 20:14:55 +09:00
Yuya Nishihara
a6393c4f55 test-command-template: rewrite recursion tests by using a map file
A literal template will be unnamed soon, so no recursion will be practically
made by using -T option.
2017-05-06 17:41:05 +09:00
Yuya Nishihara
685172007c revlog: add support for partial matching of wdir node id
The idea is simple. If the given node id prefix is 'ff...f', add +1 to the
number of matches (e.g. ambiguous if partial + maybewdir > 1).

This patch also fixes id() revset and shortest() template since _partialmatch()
can raise WdirUnsupported exception.
2016-08-19 18:26:04 +09:00
Yuya Nishihara
e952ac99ea templatefilters: fix crash by string formatting of '{x|splitlines}'
Before, it crashed because mapping['templ'] was missing. As it didn't support
the legacy list template from the beginning, we can simply use hybridlist().
2017-04-15 10:51:17 +09:00
Yuya Nishihara
35d42be491 templater: add shorthand for building a dict like {"key": key}
Like field init shorthand of Rust. This is convenient for building a JSON
object from selected keywords.

This means dict() won't support Python-like dict(iterable) syntax because
it's ambiguous. Perhaps it could be implemented as 'mapdict(xs % (k, v))'.
2017-04-03 23:13:49 +09:00
Yuya Nishihara
d86057a7bc templater: find keyword name more thoroughly on filtering error
Before, it could spill an internal representation of compiled template such
as [(<function runsymbol at 0x....>, 'extras'), ...]. Show less cryptic
message if no symbol found.

New findsymbolicname() function will be also used by dict() constructor.
2017-04-08 23:33:32 +09:00
Yuya Nishihara
ada544b9a5 templater: add dict() constructor
It's troublesome to build JSON by template, so let's add programmatic way.
2017-04-03 22:54:06 +09:00
Yuya Nishihara
073239ae67 templater: port pad() to take keyword arguments
This is another example where keyword arguments can be actually useful.
2017-04-03 22:23:52 +09:00
Yuya Nishihara
85fe439717 templater: add support for keyword arguments
Unlike revset, function arguments are pre-processed in templater. That's why
we need to define argspec per function. An argspec field looks somewhat
redundant in @templatefunc definition as a name field contains human-readable
list of arguments. I'll make function doc be built from argspec later.

Ported separate() function as an example.
2017-04-03 21:22:39 +09:00
Yuya Nishihara
1d5bb45321 templater: add parsing rule for key-value pair
Based on the revset implementation, ef14ee493cf7. This patch also adjusts
the test as '=' is now a valid token.
2017-04-03 20:55:55 +09:00
Yuya Nishihara
0aa51ecaec templater: make _hybrid provide more list/dict-like methods
So the JSON filter works.
2017-04-04 22:31:59 +09:00
Yuya Nishihara
caee220313 templater: provide loop counter as "index" keyword
This was originally written for JSON templating where we would have to be
careful to not add extra comma, but seems generally useful.

Inner loop started by % operator has its own counter.
2016-04-22 21:46:33 +09:00
Gregory Szorc
62d4252847 show: new extension for displaying various repository data
Currently, Mercurial has a number of commands to show information. And,
there are features coming down the pipe that will introduce more
commands for showing information.

Currently, when introducing a new class of data or a view that we
wish to expose to the user, the strategy is to introduce a new command
or overload an existing command, sometimes both. For example, there is
a desire to formalize the wip/smartlog/underway/mine functionality that
many have devised. There is also a desire to introduce a "topics"
concept. Others would like views of "the current stack." In the
current model, we'd need a new command for wip/smartlog/etc (that
behaves a lot like a pre-defined alias of `hg log`). For topics,
we'd likely overload `hg topic[s]` to both display and manipulate
topics.

Adding new commands for every pre-defined query doesn't scale well
and pollutes `hg help`. Overloading commands to perform read-only and
write operations is arguably an UX anti-pattern: while having all
functionality for a given concept in one command is nice, having a
single command doing multiple discrete operations is not. Furthermore,
a user may be surprised that a command they thought was read-only
actually changes something.

We discussed this at the Mercurial 4.0 Sprint in Paris and decided that
having a single command where we could hang pre-defined views of
various data would be a good idea. Having such a command would:

* Help prevent an explosion of new query-related commands
* Create a clear separation between read and write operations
  (mitigates footguns)
* Avoids overloading the meaning of commands that manipulate data
  (bookmark, tag, branch, etc) (while we can't take away the
  existing behavior for BC reasons, we now won't introduce this
  behavior on new commands)
* Allows users to discover informational views more easily by
  aggregating them in a single location
* Lowers the barrier to creating the new views (since the barrier
  to creating a top-level command is relatively high)

So, this commit introduces the `hg show` command via the "show"
extension. This command accepts a positional argument of the
"view" to show. New views can be registered with a decorator. To
prove it works, we implement the "bookmarks" view, which shows a
table of bookmarks and their associated nodes.

We introduce a new style to hold everything used by `hg show`.

For our initial bookmarks view, the output varies from `hg bookmarks`:

* Padding is performed in the template itself as opposed to Python
* Revision integers are not shown
* shortest() is used to display a 5 character node by default (as
  opposed to static 12 characters)

I chose to implement the "bookmarks" view first because it is simple
and shouldn't invite too much bikeshedding that detracts from the
evaluation of `hg show` itself. But there is an important point
to consider: we now have 2 ways to show a list of bookmarks. I'm not
a fan of introducing multiple ways to do very similar things. So it
might be worth discussing how we wish to tackle this issue for
bookmarks, tags, branches, MQ series, etc.

I also made the choice of explicitly declaring the default show
template not part of the standard BC guarantees. History has shown
that we make mistakes and poor choices with output formatting but
can't fix these mistakes later because random tools are parsing
output and we don't want to break these tools. Optimizing for human
consumption is one of my goals for `hg show`. So, by not covering
the formatting as part of BC, the barrier to future change is much
lower and humans benefit.

There are some improvements that can be made to formatting. For
example, we don't yet use label() in the templates. We obviously
want this for color. But I'm not sure if we should reuse the existing
log.* labels or invent new ones. I figure we can punt that to a
follow-up.

At the aforementioned Sprint, we discussed and discarded various
alternatives to `hg show`.

We considered making `hg log <view>` perform this behavior. The main
reason we can't do this is because a positional argument to `hg log`
can be a file path and if there is a conflict between a path name and
a view name, behavior is ambiguous. We could have introduced
`hg log --view` or similar, but we felt that required too much typing
(we don't want to require a command flag to show a view) and wasn't
very discoverable. Furthermore, `hg log` is optimized for showing
changelog data and there are things that `hg display` could display
that aren't changelog centric.

There were concerns about using "show" as the command name.

Some users already have a "show" alias that is similar to `hg export`.

There were also concerns that Git users adapted to `git show` would
be confused by `hg show`'s different behavior. The main difference
here is `git show` prints an `hg export` like view of the current
commit by default and `hg show` requires an argument. `git show`
can also display any Git object. `git show` does not support
displaying more complex views: just single objects. If we
implemented `hg show <hash>` or `hg show <identifier>`, `hg show`
would be a superset of `git show`. Although, I'm hesitant to do that
at this time because I view `hg show` as a higher-level querying
command and there are namespace collisions between valid identifiers
and registered views.

There is also a prefix collision with `hg showconfig`, which is an
alias of `hg config`.

We also considered `hg view`, but that is already used by the "hgk"
extension.

`hg display` was also proposed at one point. It has a prefix collision
with `hg diff`. General consensus was "show" or "view" are the best
verbs. And since "view" was taken, "show" was chosen.

There are a number of inline TODOs in this patch. Some of these
represent decisions yet to be made. Others represent features
requiring non-trivial complexity. Rather than bloat the patch or
invite additional bikeshedding, I figured I'd document future
enhancements via TODO so we can get a minimal implmentation landed.
Something is better than nothing.
2017-03-24 19:19:00 -07:00
Yuya Nishihara
32e72957d2 templater: make pad() strip color codes before computing width (issue5416)
Tested in ANSI mode. We might have to extend _ansieffectre to support
terminfo mode.
2017-03-18 21:02:20 +09:00
Yuya Nishihara
b5783c4070 templater: make pad() compute actual width
str.ljust() and .rjust() are based on byte length, which are valid only for
ASCII characters.
2017-03-18 20:50:15 +09:00
Yuya Nishihara
469d1e92a3 templater: reject bad fillchar argument passed to pad()
Otherwise TypeError would be raised.
2017-03-18 20:38:44 +09:00
Yuya Nishihara
5af4f5ecfd color: insert color code after every "\e[0m" (issue5413)
This assumes the last color wins, tested in ANSI mode. I guess terminfo mode
would work in the same way.
2017-03-18 20:11:15 +09:00
Matt Harbison
c6639930d0 tests: update globs for Windows
The extra glob in test-command-template.t caused it to say no result was
reported.  It used to be (within the past year), that both this and the missing
glob cases could be fixed simply by editing any output in the test, and
re-running it in interactive mode.  But that no longer works, and I had to diff
*.t against *.t.err.  I didn't dig into what changed.
2017-01-08 13:49:53 -05:00
FUJIWARA Katsunori
8b10b9dd7e tests: use basic format code "%Y" instead of "%s" for test portability
On Windows, strftime() doesn't support format code "%s", and it causes
"invalid format string" error.

    https://msdn.microsoft.com/en-us/library/fe06s4ak.aspx

test-command-template.t examines not seconds value in UTC, but
arithmetic calculation. Therefore, using format code "%Y" instead of
"%s" should be reasonable.

FYI:

- Python standard library reference doesn't list "%s" up in format
  code list required for "C standard (1989 version)", even though it
  also mentions that additional format codes are required for "C
  standard (1999 version)"

  https://docs.python.org/2.7/library/datetime.html#strftime-and-strptime-behavior

- The Open Group Base Specifications Issue 7 (IEEE Std 1003.1-2008,
  2016 Edition) doesn't require strftime to support format code "%s"

  http://pubs.opengroup.org/onlinepubs/9699919799/functions/strftime.html

- "man strftime" of (Open/Oracle) Solaris and Mac OS X (= UNIX
  certified OSs) describes about format code "%s"
2016-10-30 06:15:07 +09:00
Yuya Nishihara
01ff276025 templater: use unfiltered changelog to calculate shortest() at constant time
cl._partialmatch() can be pretty slow if hidden revisions are involved. This
patch cancels the slowdown introduced by the previous patch by using an
unfiltered changelog, which means shortest(node) isn't always the shortest.

The result isn't perfect, but seems okay as long as shortest(node) is short
enough to type and can be used as an identifier.

  (with hidden revisions)
  % hg log -R hg-committed -r0:20000 -T '{node|shortest}\n' --time > /dev/null
  (.^^) time: real 1.530 secs (user 1.480+0.000 sys 0.040+0.000)
  (.^)  time: real 43.080 secs (user 43.060+0.000 sys 0.030+0.000)
  (.)   time: real 1.680 secs (user 1.650+0.000 sys 0.020+0.000)
2016-10-25 21:49:30 +09:00
Yuya Nishihara
35fcce9afc templater: do not use index.partialmatch() directly to calculate shortest()
cl.index.partialmatch() isn't a drop-in replacement for cl._partialmatch().
It has no knowledge about hidden revisions, and it raises ValueError if a node
shorter than 4 chars is given. Instead, use index.partialmatch() through
cl._partialmatch(), which has no such problems and gives the identical result
with/without --pure.

The test output was sampled with --pure without this patch, which shows the
most correct result. However, we'll need to switch to using an unfiltered
changelog because _partialmatch() of a filtered changelog can be an order of
magnitude slower.

  (with hidden revisions)
  % hg log -R hg-committed -r0:20000 -T '{node|shortest}\n' --time > /dev/null
  (.^)  time: real 1.530 secs (user 1.480+0.000 sys 0.040+0.000)
  (.)   time: real 43.080 secs (user 43.060+0.000 sys 0.030+0.000)
2016-10-23 14:05:23 +09:00
Simon Farnsworth
d5bf3ea399 templater: provide arithmetic operations on integers
The termwidth template keyword is of limited use without some way to ensure
that margins are respected.

Provide a full set of arithmetic operators (four basic operations plus the
mod function, defined to match Python's // for division), so that you can
create termwidth based layouts that match the user's terminal size
2016-10-09 05:51:04 -07:00
Simon Farnsworth
c7fbc87ac7 template: provide a termwidth keyword (issue5395)
We want to provide terminal-sized output. As a starting point, expose the
terminal width to the templater for use in things like fill.
2016-10-08 02:26:48 -07:00
Yuya Nishihara
5196f3da90 templater: add relpath() to convert repo path to relative path (issue5394)
File paths in template are repository-absolute paths. This function can be
used to convert them to filesystem paths relative to cwd. This also converts
'/' to '\\' on Windows.
2016-10-08 15:24:26 +02:00
Hannes Oldenburg
d853961750 templates: add built-in files() function
We already support multiple primitive for listing files, which were
affected by the current changeset.
This patch adds files() which returns files of the current changeset
matching a given pattern or fileset query via the "set:" prefix.
2016-09-23 08:15:05 +00:00
Matt Mackall
6041ad2e9e templater: add template path to __base__ search
This does a fall-back check for style files or directories that are
in Mercurial's template path for user convenience.

We intentionally don't use this for the built-in coal style because we don't
want the style to mysteriously break if the working directory just
happens to have a file named "paper".
2016-08-24 17:43:45 -07:00
Yuya Nishihara
f9c7bd7213 templater: make pad() evaluate boolean argument (BC)
Otherwise it would crash if template expression was passed.

This patch unifies the way how boolean expression is evaluated, which involves
BC. Before "if(true)" and "pad(..., 'false')" were False, which are now True
since they are boolean literal and non-empty string respectively.

"func is runsymbol" is the same hack as evalstringliteral(), which is needed
for label() to take color literals.
2016-04-22 21:29:13 +09:00
Matt Mackall
6fad3ce25a date: refactor timezone parsing
We want to be able to accept ISO 8601 style timezones that don't
include a space separator, so we change the timezone parsing function
to accept a full date string and return both the offset and the
non-timezone portion.
2016-07-27 15:14:19 -05:00
Yuya Nishihara
1c24b2522b templatekw: fix join format of parents keyword (issue5292)
Since the default joinfmt() can't process a dict of multiple keywords, we
need a dedicated joinfmt for showparents().

Unlike revset(), parents are formatted as '{rev}:{node|formatnode}' by default.
We copy the default formatting just like showextras() and showfilecopies() do.
2016-07-22 22:12:12 +09:00
Yuya Nishihara
9bf038789f templatekw: fix join format of revset() function
It's been broken since eef3c19484ca, which made makemap() return a dict of
multiple keywords. Because the default joinfmt() randomly picks one item
from a dict, we have to make revset() select d[name] explicitly.
2016-07-22 22:00:46 +09:00
Martin von Zweigbergk
f553986d8e templater: add separate() template function
A pretty common pattern in templates is adding conditional separators
like so:

  {node}{if(bookmarks, " {bookmarks}")}{if(tags, " {tags}")}

With this patch, the above can be simplified to:

  {separate(" ", node, bookmarks, tags)}

The function is similar to the already existing join(), but with a few
differences:

 * separate() skips empty arguments

 * join() expects a single list argument, while separate() expects
   each item as a separate argument

 * separate() takes the separator first in order to allow a variable
   number of arguments after it
2016-05-03 09:49:54 -07:00
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