Commit Graph

207 Commits

Author SHA1 Message Date
Yuya Nishihara
366ad4616f templater: wrap get/min/max result so map operation can apply to element
See the test for usage example.

wraphybridvalue() takes a key/value pair because a hybrid dict passes a key
to its makemap() function. Since makemap() of showmanifest() doesn't need
a key, it's set to None.
2017-09-09 19:13:25 +09:00
Yuya Nishihara
7dafbbbbcf templatekw: add new-style template expansion to {manifest}
The goal is to allow us to easily access to nested data. The dot operator
will be introduced later so we can write '{p1.files}' instead of
'{revset("p1()") % "{files}"}' for example.

In the example above, 'p1' needs to carry a mapping dict along with its
string representation. If it were a list or a dict, it could be wrapped
semi-transparently with the _hybrid class, but for non-list/dict types,
it would be difficult to proxy all necessary functions to underlying value
type because several core operations may conflict with the ones of the
underlying value:

 - hash(value) should be different from hash(wrapped(value)), which means
   dict[wrapped(value)] would be invalid
 - 'value == wrapped(value)' would be false, breaks 'ifcontains'
 - len(wrapped(value)) may be either len(value) or len(iter(wrapped(value)))

So the wrapper has no proxy functions and its scope designed to be minimal.
It's unwrapped at eval*() functions so we don't have to care for a wrapped
object unless it's really needed:

  # most template functions just call evalfuncarg()
  unwrapped_value = evalfuncarg(context, mapping, args[n])
  # if wrapped value is needed, use evalrawexp()
  maybe_wrapped_value = evalrawexp(context, mapping, args[n])

Another idea was to wrap every template variable with a tagging class, but
which seemed uneasy without a static type checker.

This patch updates {manifest} to a mappable as an example.
2016-04-24 18:41:23 +09:00
Yuya Nishihara
c22459dc5d templater: adjust binding strength of '%' and '|' operators (BC)
This makes 'foo|bar%baz' parsed as '(foo|bar)%baz', not 'foo|(bar%baz)'.
Perhaps it was a mistake that '%' preceded '|'. Both '|' and '%' can be
considered a kind of function application, and '|' is more like a '.' operator
seen in OO languages. So IMHO '|' should have the same (or higher) binding as
'%'.

The BC breakage should be minimal since both '|' and '%' operators have
strict requirements for their operands and 'foo|bar%baz' was invalid:

 - right-hand side of '|' must be a symbol
 - left-hand side of '%' must be a dict or list
 - right-hand side of '%' must be a string or symbol
2017-04-24 21:37:11 +09:00
Yuya Nishihara
f0fc1531a4 parser: stabilize output of prettyformat() by using byte-safe repr()
The format of leaf nodes is slightly changed so they look more similar to
internal nodes.
2017-09-03 21:17:25 +09:00
Augie Fackler
3bf0b90e12 tests: update test-command-template to pass our import checker 2017-08-22 15:49:54 -04:00
Sean Farley
e18a90ab08 merge with stable 2017-08-21 21:35:06 -07:00
Martin von Zweigbergk
7cd70adbc1 templatekw: choose {latesttag} by len(changes), not date (issue5659)
As Augie reported in the bug, the current heuristic of choosing the
best tag of a merge commit by taking the one with newest tag (in terms
of tagging date) currently fails in the Mercurial repo itself. Copying
the example from Yuya:

  $ hg glog -T '{node|short} {latesttag}+{latesttagdistance}\n' \
    -r '4.2.3: & (merge() + parents(merge()) + tag())'
  o    cc59efae4cc0 4.2.3+5
  |\
  | o    06f60e88fc3a 4.2.3+4
  | |\
  | | o  c191a9eb0b10 4.3-rc+109
  | | |
  | | ~
  o |  49ada93fdc10 4.3.1+2
  : |
  o |  229937197835 4.3.1+0
  |/
  o    6a83ad94c0f2 4.2.3+3
  |\
  | ~
  o  8e9dcdd1de74 4.2.3+2
  :
  o  525f2b18248f 4.2.3+0
  |
  ~

It seems to me like the best choice is the tag with the smallest
number of changes since it (across all paths, not the longest single
path). So that's what this patch does, even though it's
costly. Best-of-5 timings for Yuya's command above shows a slowdown
from 1.293s to 1.610s. We can optimize it later.

Differential Revision: https://phab.mercurial-scm.org/D447
2017-08-15 23:23:55 -07:00
Martin von Zweigbergk
8bb8bc19bb tests: use graph log in {latesttag} tests
The tests are much easier to read if one does not have to re-read the
setup part all the time to understand the graph shape.

Differential Revision: https://phab.mercurial-scm.org/D446
2017-08-18 12:50:26 -07:00
Danny Hooper
54e3286e1e log: add a "graphwidth" template variable
Wrapping text in templates for 'hg log --graph' can't be done very well,
because the template doesn't know how wide the graph drawing is. The edge
drawing function needs to know the number of lines in the template output, so
we need to also determine how wide that drawing would be before we call the
edgefn or evaluate the template.

This patch makes edgefn compute the graph width and pass it into the template
so that we can do something like this:

COLUMNS=10 hg log --graph --template "{fill(desc, termwidth - graphwidth)}"
@  a a a a
|  a a a a
|  a a a a
o    a a a
|\   a a a
| |  a a a
| |  a a a

Using extensions to do this would be relatively complicated due to a lack of
hooks in this area of the code.

In the future it may make sense to have a more generic "textwidth" that tells
you how many columns you can expect to fill without causing the terminal to
wrap your output. I'm not sure there are other situations to motivate this yet,
or if it is entirely feasible.

Differential Revision: https://phab.mercurial-scm.org/D360
2017-08-15 10:15:31 -07:00
Boris Feld
c886c86073 test: update evolution config
evolution* config has been rewritten in stabilization* in the previous patch,
update tests file to use the new names.

Differential Revision: https://phab.mercurial-scm.org/D249
2017-08-04 18:41:16 +02:00
Boris Feld
b989852f8f debugobsolete: also report the number of obsoleted changesets
This seems useful to have the number of obsoleted changesets when calling
debugobsolete.
2017-07-16 02:33:14 +02:00
Augie Fackler
3112944d5b tests: replace yet more calls to python with $PYTHON
These are some simple cases. More to come in a future change.

Reviewers: krbullock

Reviewed By: krbullock

Differential Revision: https://phab.mercurial-scm.org/D4
2017-07-05 11:10:11 -05:00
Gregory Szorc
6c60659b4c namespaces: record and expose whether namespace is built-in
Currently, the templating layer tends to treat each namespace
as a one-off, with explicit usage of {bookmarks}, {tags}, {branch},
etc instead of using {namespaces}. It would be really useful if
we could iterate over namespaces and operate on them generically.
However, some consumers may wish to differentiate namespaces by
whether they are built-in to core Mercurial or provided by extensions.
Expected use cases include ignoring non-built-in namespaces or
emitting a generic label for non-built-in namespaces.

This commit introduces an attribute on namespace instances
that says whether the namespace is "built-in" and then exposes
this to the templating layer.

As part of this, we implement a reusable extension for defining
custom names on each changeset for testing. A second consumer
will be introduced in a subsequent commit.
2017-06-24 14:52:15 -07:00
Gregory Szorc
da11a0810d templatekw: expose color name in {namespaces} entries
Templates make use of a "log.<namespace>" label. The <namespace> value
here differs from the actual namespace name in that the namespace
itself is plural but the label/color value is singular.

Expose the color name to the templating layer so log.* labels
can be emitted for {namespaces}.

As part of this, we refactored the logic to eliminate a gnarly
comprehension. We store color names in their own dict because the
lookup can occur in tight loops and we shouldn't have to go to
repo.names[ns] multiple times for every changeset.
2017-06-24 13:39:20 -07:00
Yuya Nishihara
64e5f1d0a7 changeset_templater: backport parts map of [templates] section from formatter 2017-04-22 21:16:08 +09:00
Yuya Nishihara
b8fff410fd changeset_templater: backport separator template from formatter
As commented, this should be used with docheader and docfooter, not with
header nor footer. That's one reason why no props are passed to templater
when rendering a separator. (See map-cmdline.changelog to understand what
the "header" is.)
2017-06-17 16:32:20 +09:00
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