<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Mar 22, 2017 at 7:38 AM, Ryan McElroy <span dir="ltr"><<a href="mailto:rm@fb.com" target="_blank">rm@fb.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On 3/22/17 6:49 AM, Gregory Szorc wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
# HG changeset patch<br>
# User Gregory Szorc <<a href="mailto:gregory.szorc@gmail.com" target="_blank">gregory.szorc@gmail.com</a>><br>
# Date 1490165337 25200<br>
#      Tue Mar 21 23:48:57 2017 -0700<br>
# Node ID 80ca2bee4a06887f918e3328b3f005<wbr>e4c1cb1ab1<br>
# Parent  ae796e23fd42b036352b298f570af8<wbr>949c2db2d9<br>
show: new extension for displaying various repository data<br>
<br>
Currently, Mercurial has a number of commands to show information. And,<br>
there are features coming down the pipe that will introduce more<br>
commands for showing information.<br>
<br>
Currently, when introducing a new class of data or a view that we<br>
wish to expose to the user, the strategy is to introduce a new command<br>
or overload an existing command, sometimes both. For example, there is<br>
a desire to formalize the wip/smartlog/underway/mine functionality that<br>
many have devised. There is also a desire to introduce a "topics"<br>
concept. Others would like views of "the current stack." In the<br>
current model, we'd need a new command for wip/smartlog/etc (that<br>
behaves a lot like a pre-defined alias of `hg log`). For topics,<br>
we'd likely overload `hg topic[s]` to both display and manipulate<br>
topics.<br>
<br>
Adding new commands for every pre-defined query doesn't scale well<br>
and pollutes `hg help`. Overloading commands to perform read-only and<br>
write operations is arguably an UX anti-pattern: while having all<br>
functionality for a given concept in one command is nice, having a<br>
single command doing multiple discrete operations is not. Furthermore,<br>
a user may be surprised that a command they thought was read-only<br>
actually changes something.<br>
<br>
We discussed this at the Mercurial 4.0 Sprint in Paris and decided that<br>
having a single command where we could hang pre-defined views of<br>
various data would be a good idea. Having such a command would:<br>
<br>
* Help prevent an explosion of new query-related commands<br>
* Create a clear separation between read and write operations<br>
   (mitigates footguns)<br>
* Avoids overloading the meaning of commands that manipulate data<br>
   (bookmark, tag, branch, etc) (while we can't take away the<br>
   existing behavior for BC reasons, we now won't introduce this<br>
   behavior on new commands)<br>
</blockquote></div></div>
I'm not convinced that these "footguns" are a bad ui though. I certainly would be less comfortable asking people who are used to writing "hg boo" to change to "hg show bookmarks" (see comment on<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
* Allows users to discover informational views more easily by<br>
   aggregating them in a single location<br>
* Lowers the barrier to creating the new views (since the barrier<br>
   to creating a top-level command is relatively high)<br>
<br>
So, this commit introduces the `hg show` command via the "show"<br>
extension. This command accepts a positional argument of the<br>
"view" to show. New views can be registered with a decorator. To<br>
prove it works, we implement the "bookmarks" view, which shows a<br>
table of bookmarks and their associated nodes.<br>
<br>
We introduce a new style to hold everything used by `hg show`.<br>
</blockquote></span>
Ah, this answers some of my inline questions below about the new styles.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
For our initial bookmarks view, the output varies from `hg bookmarks`:<br>
<br>
* Padding is performed in the template itself as opposed to Python<br>
* Revision integers are not shown<br>
* shortest() is used to display a 5 character node by default (as<br>
   opposed to static 12 characters)<br>
<br>
I chose to implement the "bookmarks" view first because it is simple<br>
and shouldn't invite too much bikeshedding that detracts from the<br>
evaluation of `hg show` itself. But there is an important point<br>
to consider: we now have 2 ways to show a list of bookmarks. I'm not<br>
a fan of introducing multiple ways to do very similar things. So it<br>
might be worth discussing how we wish to tackle this issue for<br>
bookmarks, tags, branches, MQ series, etc.<br>
</blockquote></span>
I'm pretty concerned about this too. I don't have an answer right now but I'll think about it.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
I also made the choice of explicitly declaring the default show<br>
template not part of the standard BC guarantees. History has shown<br>
that we make mistakes and poor choices with output formatting but<br>
can't fix these mistakes later because random tools are parsing<br>
output and we don't want to break these tools. Optimizing for human<br>
consumption is one of my goals for `hg show`. So, by not covering<br>
the formatting as part of BC, the barrier to future change is much<br>
lower and humans benefit.<br>
</blockquote></span>
This is awesome. See inline comments for additional idea. First "porcelain" hg command :-p.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
There are some improvements that can be made to formatting. For<br>
example, we don't yet use label() in the templates. We obviously<br>
want this for color. But I'm not sure if we should reuse the existing<br>
log.* labels or invent new ones. I figure we can punt that to a<br>
follow-up.<br>
</blockquote></span>
Seems that this patch is good for collecting shed colors, but this would probably want to be broken up into a series before it actually goes in, right?</blockquote><div><br></div><div>I figured this patch would land as a big chunk and we'd iterate using the normal process. I think trying to split the initial landing into multiple parts is a bit difficult because there's a lot to take in. But if people want me to split it, I can.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5"><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
At the aforementioned Sprint, we discussed and discarded various<br>
alternatives to `hg show`.<br>
<br>
We considered making `hg log <view>` perform this behavior. The main<br>
reason we can't do this is because a positional argument to `hg log`<br>
can be a file path and if there is a conflict between a path name and<br>
a view name, behavior is ambiguous. We could have introduced<br>
`hg log --view` or similar, but we felt that required too much typing<br>
(we don't want to require a command flag to show a view) and wasn't<br>
very discoverable. Furthermore, `hg log` is optimized for showing<br>
changelog data and there are things that `hg display` could display<br>
that aren't changelog centric.<br>
<br>
There were concerns about using "show" as the command name.<br>
<br>
Some users already have a "show" alias that is similar to `hg export`.<br>
<br>
There were also concerns that Git users adapted to `git show` would<br>
be confused by `hg show`'s different behavior. The main difference<br>
here is `git show` prints an `hg export` like view of the current<br>
commit by default and `hg show` requires an argument. `git show`<br>
can also display any Git object. `git show` does not support<br>
displaying more complex views: just single objects. If we<br>
implemented `hg show <hash>` or `hg show <identifier>`, `hg show`<br>
would be a superset of `git show`. Although, I'm hesitant to do that<br>
at this time because I view `hg show` as a higher-level querying<br>
command and there are namespace collisions between valid identifiers<br>
and registered views.<br>
<br>
There is also a prefix collision with `hg showconfig`, which is an<br>
alias of `hg config`.<br>
</blockquote></div></div>
I'm not too concerned about this. As I said in the other thread, fb has a show extension as well. It's basically a thin wrapper around `hg log -vpr` that allows a few additional flags and has a default '.' parameter: <a href="https://bitbucket.org/facebook/hg-experimental/src/default/hgext3rd/show.py" rel="noreferrer" target="_blank">https://bitbucket.org/facebook<wbr>/hg-experimental/src/default/<wbr>hgext3rd/show.py</a><span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
We also considered `hg view`, but that is already used by the "hgk"<br>
extension.<br>
</blockquote></span>
Meh. Can we deprecate hgk? (Serious question: I don't know how widely it's used. We seem to have it installed at FB but it seems totally broken and nobody has ever complained so it seems that out of thousands of users nobody has ever noticed it's there).<span class=""><br></span></blockquote><div><br></div><div>I'm not opposed to renaming this `hg view`. But I'd prefer that be done as a follow-up because I want to get this "framework" landed!<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
`hg display` was also proposed at one point. It has a prefix collision<br>
with `hg diff`. General consensus was "show" or "view" are the best<br>
verbs. And since "view" was taken, "show" was chosen.<br>
</blockquote></span>
Seems reasonable. Feel free to ignore my bikeshedding above. I'm okay with show overall.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
diff --git a/contrib/wix/templates.wxs b/contrib/wix/templates.wxs<br>
--- a/contrib/wix/templates.wxs<br>
+++ b/contrib/wix/templates.wxs<br>
@@ -32,6 +32,7 @@<br>
            <File Name="map-cmdline.changelog" KeyPath="yes" /><br>
            <File Name="map-cmdline.compact" /><br>
            <File Name="map-cmdline.default" /><br>
+          <File Name="map-cmdline.show" /><br>
            <File Name="map-cmdline.bisect" /><br>
            <File Name="map-cmdline.xml" /><br>
            <File Name="map-cmdline.status" /><br>
</blockquote></span>
What are these files? I'm not familiar with what's going on here.</blockquote><div><br></div><div>The map-cmdline.* files are various styles that can be used with -T. I invented a new style for this command. I'm not sure that if this is proper. Yuya already directed me to not have various template names conflict with built-in templates (hence the "show*" prefixing). So perhaps I could roll these templates into map-cmdline.default?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5"><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
diff --git a/hgext/show.py b/hgext/show.py<br>
new file mode 100644<br>
--- /dev/null<br>
+++ b/hgext/show.py<br>
@@ -0,0 +1,115 @@<br>
+# show.py - Extension implementing `hg show`<br>
+#<br>
+# Copyright 2017 Gregory Szorc <<a href="mailto:gregory.szorc@gmail.com" target="_blank">gregory.szorc@gmail.com</a>><br>
+#<br>
+# This software may be used and distributed according to the terms of the<br>
+# GNU General Public License version 2 or any later version.<br>
+<br>
+"""unified command to show various repository information (EXPERIMENTAL)<br>
+<br>
+This extension provides the :hg:`show` command, which provides a central<br>
+command for displaying commonly-accessed repository data and views of that<br>
+data.<br>
+"""<br>
+<br>
+from __future__ import absolute_import<br>
+<br>
+from mercurial.i18n import _<br>
+from mercurial import (<br>
+    cmdutil,<br>
+    commands,<br>
+    error,<br>
+    registrar,<br>
+)<br>
+<br>
+# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for<br>
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should<br>
+# be specifying the version(s) of Mercurial they are tested with, or<br>
+# leave the attribute unspecified.<br>
+testedwith = 'ships-with-hg-core'<br>
+<br>
+cmdtable = {}<br>
+command = cmdutil.command(cmdtable)<br>
+<br>
+class showcmdfunc(registrar._funcreg<wbr>istrarbase):<br>
+    """Register a function to be invoked for an `hg show <thing>`."""<br>
+    _docformat = '%s -- %s'<br>
</blockquote></div></div>
Unused variable?<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+    def _extrasetup(self, name, func, fmtopic=None):<br>
+        func._fmtopic = fmtopic<br>
</blockquote></span>
Docstring please -- I have no idea what this is for. Also, it's unused?<span class=""><br></span></blockquote><div><br></div><div>This stuff is used. I'll add comments.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+showview = showcmdfunc()<br>
+<br>
+@command('show', commands.formatteropts, _('[VIEW]'))<br>
+def show(ui, repo, view=None, template=None):<br>
+    """show various repository information<br>
+<br>
+    A requested view of repository data is displayed.<br>
+<br>
+    If no view is requested, the list of available views is shown.<br>
</blockquote></span>
(and we abort)<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+    .. note::<br>
+<br>
+       The default output from this command is not covered under Mercurial's<br>
+       default backwards-compatible mechanism (which puts an emphasis on<br>
+       not changing behavior). This means output from this command may change<br>
+       in any future release. However, the values fed to the formatter are<br>
+       covered under the default backwards-compatible mechanism.<br>
+<br>
+       Automated consumers of this command should specify an explicit template<br>
+       via ``-T/--template`` to guarantee output is stable.<br>
</blockquote></span>
YES! I love it.<br>
<br>
We should consider aborting if HGPLAIN=1 and no template is specified, in fact!<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+    List of available views:<br>
+<br>
+    """<br>
+    views = showview._table<br>
+<br>
+    if not view:<br>
+        ui.write(_('available views:\n'))<br>
+        ui.write('\n')<br>
</blockquote></span>
Should this use a formatter? I could imagine wanting to consume available views in json, for example.<span class=""><br></span></blockquote><div><br></div><div>Probably. But I'm not sure how to do it though (I'm not sure how to get the header and footer printed while also printing multiple items). I've added a TODO in the next version.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+        for name, func in sorted(views.items()):<br>
+            ui.write(_('%s\n') % func.__doc__)<br>
</blockquote></span>
The entire docstring seems like too much. We should probably have only the first line of the docstring here. Also, you don't use the name. Shouldn't the name be here as well?<br></blockquote><div><br></div><div>But it's not the full docstring: that _docformat variable does magic ;)<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Nitpick: I don't think it's useful to internationalize '%s\n'.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+        ui.write('\n')<br>
+        raise error.Abort(_('no view requested'),<br>
+                          hint=_('use `hg show <view>` to choose a view'))<br>
</blockquote></span>
This hint format is different that what I usually see in hg. Shouldn't it be 'hg show VIEW' so it's consistent with our other command help output? Also, we tend to not use backticks, right?<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+    if view not in views:<br>
+        raise error.Abort(_('unknown view: %s') % view,<br>
+                          hint=_('run `hg show` to see available views'))<br>
</blockquote></span>
We should probably do prefix matching to be consistent with other commands in hg (and to help out lazy typers).<span class=""><br></span></blockquote><div><br></div><div>Agreed. I'll add a TODO (I don't want to bloat scope too much).<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+    template = template or 'show'<br>
+    fmtopic = 'show%s' % views[view]._fmtopic<br>
+<br>
+    ui.pager('show')<br>
</blockquote></span>
Why is this down here but not up where we print a list of views?<span class=""><br></span></blockquote><div><br></div><div>Will fix.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+    with ui.formatter(fmtopic, {'template': template}) as fm:<br>
+        return views[view](ui, repo, fm)<br>
+<br>
+@showview('bookmarks', fmtopic='bookmarks')<br>
+def showbookmarks(ui, repo, fm):<br>
+    """bookmarks and their associated changeset"""<br>
+    marks = repo._bookmarks<br>
+    if not len(marks):<br>
+        ui.write(_('(no bookmarks set)\n'))<br>
+        return<br>
+<br>
+    active = repo._activebookmark<br>
+    longest = max(len(b) for b in marks)<br>
+<br>
+    for bm, node in sorted(marks.items()):<br>
+        fm.startitem()<br>
+        fm.context(ctx=repo[node])<br>
+        fm.write('bookmark', '%s', bm)<br>
+        fm.write('node', fm.hexfunc(node), fm.hexfunc(node))<br>
+        fm.data(active=bm == active,<br>
+                _longestlen=longest)<br>
</blockquote></span>
_longest should probably be _longestname, because shortened nodes can also have interesting length properties -- and we may want to pass _longestnode in the future if there is more data we want to show here and we want to pad nicely.<span class=""><br></span></blockquote><div><br></div><div>Agreed. Although the longest shorted node is a bit difficult to implement because AFAICT there is no obvious function to call. I'll TODO that one.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+# Adjust the docstring of the show command so it shows all registered views.<br>
+# This is a bit hacky because it runs at the end of module load. When moved<br>
+# into core or when another extension wants to provide a view, we'll need<br>
+# to do this more robustly.<br>
+longest = max(map(len, showview._table.keys()))<br>
+for key in sorted(showview._table.keys())<wbr>:<br>
+    cmdtable['show'][0].__doc__ += ' %s   %s\n' % (<br>
+        key.ljust(longest), showview._table[key]._origdoc)<br>
</blockquote></span>
Yuck! Surely we can do better with a formatter and padding? At the very least, we can just compute this when we need to print it out and not at module load time. But it would be better to use the formatter if possible, then we get things like JSON for free.<span class=""><br></span></blockquote><div><br></div><div>Tell me about it. This ideally wants some kind of hook in the help mechanism. I didn't want to bloat scope and implement that at this juncture. I've added a TODO.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
diff --git a/mercurial/templates/map-cmdl<wbr>ine.show b/mercurial/templates/map-cmdl<wbr>ine.show<br>
new file mode 100644<br>
--- /dev/null<br>
+++ b/mercurial/templates/map-cmdl<wbr>ine.show<br>
@@ -0,0 +1,2 @@<br>
+# TODO add label() once we figure out which namespace the labels belong on.<br>
+showbookmarks = '{if(active, "*", " ")} {pad(bookmark, _longestlen + 4)}{shortest(node, 5)}\n'<br>
</blockquote></span>
What is this file?<span class=""><br></span></blockquote><div><br></div><div>Our custom style (which may or may not be needed).<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
diff --git a/tests/test-command-template.<wbr>t b/tests/test-command-template.<wbr>t<br>
--- a/tests/test-command-template.<wbr>t<br>
+++ b/tests/test-command-template.<wbr>t<br>
@@ -1108,11 +1108,11 @@ Error if no style:<br>
      $ hg log --style notexist<br>
    abort: style 'notexist' not found<br>
-  (available styles: bisect, changelog, compact, default, phases, status, xml)<br>
+  (available styles: bisect, changelog, compact, default, phases, show, status, xml)<br>
    [255]<br>
      $ hg log -T list<br>
-  available styles: bisect, changelog, compact, default, phases, status, xml<br>
+  available styles: bisect, changelog, compact, default, phases, show, status, xml<br>
    abort: specify a template<br>
    [255]<br>
</blockquote></span>
I'm confused by these test changes. Why does show show up here?</blockquote><div><br></div><div>Because this is listing available styles (the map-cmdline.* files).<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5"><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  diff --git a/tests/test-log.t b/tests/test-log.t<br>
--- a/tests/test-log.t<br>
+++ b/tests/test-log.t<br>
@@ -148,7 +148,7 @@ log on directory<br>
      $ hg log -f -l1 --style something<br>
    abort: style 'something' not found<br>
-  (available styles: bisect, changelog, compact, default, phases, status, xml)<br>
+  (available styles: bisect, changelog, compact, default, phases, show, status, xml)<br>
    [255]<br>
    -f, phases style<br>
diff --git a/tests/test-show.t b/tests/test-show.t<br>
new file mode 100644<br>
--- /dev/null<br>
+++ b/tests/test-show.t<br>
@@ -0,0 +1,111 @@<br>
+  $ cat >> $HGRCPATH << EOF<br>
+  > [extensions]<br>
+  > show =<br>
+  > EOF<br>
+<br>
+No arguments shows available views<br>
+<br>
+  $ hg init empty<br>
+  $ cd empty<br>
+  $ hg show<br>
+  available views:<br>
+<br>
+  bookmarks -- bookmarks and their associated changeset<br>
+<br>
+  abort: no view requested<br>
+  (use `hg show <view>` to choose a view)<br>
+  [255]<br>
+<br>
+`hg help show` prints available views<br>
+<br>
+  $ hg help show<br>
+  hg show [VIEW]<br>
</blockquote></div></div>
If we abort otherwise, I wouldn't say that VIEW is optional. I guess I'm against the abort overall, though...<div><div class="h5"><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+  show various repository information<br>
+<br>
+      A requested view of repository data is displayed.<br>
+<br>
+      If no view is requested, the list of available views is shown.<br>
+<br>
+      Note:<br>
+         The default output from this command is not covered under Mercurial's<br>
+         default backwards-compatible mechanism (which puts an emphasis on not<br>
+         changing behavior). This means output from this command may change in<br>
+         any future release. However, the values fed to the formatter are<br>
+         covered under the default backwards-compatible mechanism.<br>
+<br>
+         Automated consumers of this command should specify an explicit template<br>
+         via "-T/--template" to guarantee output is stable.<br>
+<br>
+      List of available views:<br>
+<br>
+       bookmarks   bookmarks and their associated changeset<br>
+<br>
+  (use 'hg help -e show' to show help for the show extension)<br>
+<br>
+  options:<br>
+<br>
+  (some details hidden, use --verbose to show complete help)<br>
+<br>
+Unknown view prints error<br>
+<br>
+  $ hg show badview<br>
+  abort: unknown view: badview<br>
+  (run `hg show` to see available views)<br>
+  [255]<br>
+<br>
+  $ cd ..<br>
+<br>
+bookmarks view with no bookmarks prints empty message<br>
+<br>
+  $ hg init books<br>
+  $ cd books<br>
+  $ touch f0<br>
+  $ hg -q commit -A -m initial<br>
+<br>
+  $ hg show bookmarks<br>
+  (no bookmarks set)<br>
+<br>
+bookmarks view shows bookmarks in an aligned table<br>
+<br>
+  $ echo book1 > f0<br>
+  $ hg commit -m 'commit for book1'<br>
+  $ echo book2 > f0<br>
+  $ hg commit -m 'commit for book2'<br>
+<br>
+  $ hg bookmark -r 1 book1<br>
+  $ hg bookmark a-longer-bookmark<br>
+<br>
+  $ hg show bookmarks<br>
+  * a-longer-bookmark    7b570<br>
+    book1                b757f<br>
+<br>
+Bookmarks plain view<br>
+<br>
+  $ HGPLAIN= hg show bookmarks<br>
+  * a-longer-bookmark    7b570<br>
+    book1                b757f<br>
</blockquote></div></div>
Let's make this abort instead.<div class="HOEnZb"><div class="h5"><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+A custom bookmarks template works<br>
+<br>
+  $ hg show bookmarks -T '{node} {bookmark} {active}\n'<br>
+  7b5709ab64cbc34da9b4367b64afff<wbr>47f2c4ee83 a-longer-bookmark True<br>
+  b757f780b8ffd71267c6ccb32e0882<wbr>d9d32a8cc0 book1 False<br>
+<br>
+bookmarks JSON works<br>
+<br>
+  $ hg show bookmarks -T json<br>
+  [<br>
+   {<br>
+    "active": true,<br>
+    "bookmark": "a-longer-bookmark",<br>
+    "node": "7b5709ab64cbc34da9b4367b64aff<wbr>f47f2c4ee83"<br>
+   },<br>
+   {<br>
+    "active": false,<br>
+    "bookmark": "book1",<br>
+    "node": "b757f780b8ffd71267c6ccb32e088<wbr>2d9d32a8cc0"<br>
+   }<br>
+  ]<br>
+<br>
+  $ cd ..<br>
</blockquote>
<br>
</div></div></blockquote></div><br></div></div>