show: implement underway view
This is the beginning of a wip/smartlog view. It is basically a manually
constructed (read: fast) revset function to collect "relevant"
changesets combined with a custom template and a graph displayer.
It obviously needs a lot of work.
I'd like to get *something* usable in 4.2 so `hg show` has some value
to end-users.
Let the bikeshedding begin.
--- a/hgext/show.py Wed Apr 12 20:28:44 2017 -0700
+++ b/hgext/show.py Wed Apr 12 20:31:15 2017 -0700
@@ -15,13 +15,17 @@
from __future__ import absolute_import
from mercurial.i18n import _
+from mercurial.node import nullrev
from mercurial import (
cmdutil,
commands,
error,
formatter,
+ graphmod,
pycompat,
registrar,
+ revset,
+ revsetlang,
)
# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
@@ -32,6 +36,7 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+revsetpredicate = registrar.revsetpredicate()
class showcmdfunc(registrar._funcregistrarbase):
"""Register a function to be invoked for an `hg show <thing>`."""
@@ -128,6 +133,70 @@
fm.data(active=bm == active,
longestbookmarklen=longestname)
+@revsetpredicate('_underway([commitage[, headage]])')
+def underwayrevset(repo, subset, x):
+ args = revset.getargsdict(x, 'underway', 'commitage headage')
+ if 'commitage' not in args:
+ args['commitage'] = None
+ if 'headage' not in args:
+ args['headage'] = None
+
+ # We assume callers of this revset add a topographical sort on the
+ # result. This means there is no benefit to making the revset lazy
+ # since the topographical sort needs to consume all revs.
+ #
+ # With this in mind, we build up the set manually instead of constructing
+ # a complex revset. This enables faster execution.
+
+ # Mutable changesets (non-public) are the most important changesets
+ # to return. ``not public()`` will also pull in obsolete changesets if
+ # there is a non-obsolete changeset with obsolete ancestors. This is
+ # why we exclude obsolete changesets from this query.
+ rs = 'not public() and not obsolete()'
+ rsargs = []
+ if args['commitage']:
+ rs += ' and date(%s)'
+ rsargs.append(revsetlang.getstring(args['commitage'],
+ _('commitage requires a string')))
+
+ mutable = repo.revs(rs, *rsargs)
+ relevant = revset.baseset(mutable)
+
+ # Add parents of mutable changesets to provide context.
+ relevant += repo.revs('parents(%ld)', mutable)
+
+ # We also pull in (public) heads if they a) aren't closing a branch
+ # b) are recent.
+ rs = 'head() and not closed()'
+ rsargs = []
+ if args['headage']:
+ rs += ' and date(%s)'
+ rsargs.append(revsetlang.getstring(args['headage'],
+ _('headage requires a string')))
+
+ relevant += repo.revs(rs, *rsargs)
+
+ # Add working directory parent.
+ wdirrev = repo['.'].rev()
+ if wdirrev != nullrev:
+ relevant += revset.baseset(set([wdirrev]))
+
+ return subset & relevant
+
+@showview('underway', fmtopic='underway')
+def showunderway(ui, repo, fm):
+ """changesets that aren't finished"""
+ # TODO support date-based limiting when calling revset.
+ revs = repo.revs('sort(_underway(), topo)')
+
+ revdag = graphmod.dagwalker(repo, revs)
+ displayer = cmdutil.changeset_templater(ui, repo, None, None,
+ tmpl=fm._t.load(fm._topic),
+ mapfile=None, buffered=True)
+
+ ui.setconfig('experimental', 'graphshorten', True)
+ cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
+
# Adjust the docstring of the show command so it shows all registered views.
# This is a bit hacky because it runs at the end of module load. When moved
# into core or when another extension wants to provide a view, we'll need
--- a/mercurial/templates/map-cmdline.show Wed Apr 12 20:28:44 2017 -0700
+++ b/mercurial/templates/map-cmdline.show Wed Apr 12 20:31:15 2017 -0700
@@ -1,2 +1,3 @@
# TODO add label() once we figure out which namespace the labels belong on.
showbookmarks = '{if(active, "*", " ")} {pad(bookmark, longestbookmarklen + 4)}{shortest(node, 5)}\n'
+showunderway = '{shortest(node, 5)}{if(branches, " ({branch})")}{if(bookmarks, " ({bookmarks})")} {desc|firstline}'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-show-underway.t Wed Apr 12 20:31:15 2017 -0700
@@ -0,0 +1,168 @@
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > show =
+ > EOF
+
+ $ hg init repo0
+ $ cd repo0
+
+Command works on an empty repo
+
+ $ hg show underway
+
+Single draft changeset shown
+
+ $ echo 0 > foo
+ $ hg -q commit -A -m 'commit 0'
+
+ $ hg show underway
+ @ 9f171 commit 0
+
+Even when it isn't the wdir
+
+ $ hg -q up null
+
+ $ hg show underway
+ o 9f171 commit 0
+
+Single changeset is still there when public because it is a head
+
+ $ hg phase --public -r 0
+ $ hg show underway
+ o 9f171 commit 0
+
+A draft child will show both it and public parent
+
+ $ hg -q up 0
+ $ echo 1 > foo
+ $ hg commit -m 'commit 1'
+
+ $ hg show underway
+ @ 181cc commit 1
+ o 9f171 commit 0
+
+Multiple draft children will be shown
+
+ $ echo 2 > foo
+ $ hg commit -m 'commit 2'
+
+ $ hg show underway
+ @ 128c8 commit 2
+ o 181cc commit 1
+ o 9f171 commit 0
+
+Bumping first draft changeset to public will hide its parent
+
+ $ hg phase --public -r 1
+ $ hg show underway
+ @ 128c8 commit 2
+ o 181cc commit 1
+ |
+ ~
+
+Multiple DAG heads will be shown
+
+ $ hg -q up -r 1
+ $ echo 3 > foo
+ $ hg commit -m 'commit 3'
+ created new head
+
+ $ hg show underway
+ @ f0abc commit 3
+ | o 128c8 commit 2
+ |/
+ o 181cc commit 1
+ |
+ ~
+
+Even when wdir is something else
+
+ $ hg -q up null
+
+ $ hg show underway
+ o f0abc commit 3
+ | o 128c8 commit 2
+ |/
+ o 181cc commit 1
+ |
+ ~
+
+Draft child shows public head (multiple heads)
+
+ $ hg -q up 0
+ $ echo 4 > foo
+ $ hg commit -m 'commit 4'
+ created new head
+
+ $ hg show underway
+ @ 668ca commit 4
+ | o f0abc commit 3
+ | | o 128c8 commit 2
+ | |/
+ | o 181cc commit 1
+ |/
+ o 9f171 commit 0
+
+ $ cd ..
+
+Branch name appears in output
+
+ $ hg init branches
+ $ cd branches
+ $ echo 0 > foo
+ $ hg -q commit -A -m 'commit 0'
+ $ echo 1 > foo
+ $ hg commit -m 'commit 1'
+ $ echo 2 > foo
+ $ hg commit -m 'commit 2'
+ $ hg phase --public -r .
+ $ hg -q up -r 1
+ $ hg branch mybranch
+ marked working directory as branch mybranch
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo 3 > foo
+ $ hg commit -m 'commit 3'
+ $ echo 4 > foo
+ $ hg commit -m 'commit 4'
+
+ $ hg show underway
+ @ f8dd3 (mybranch) commit 4
+ o 90cfc (mybranch) commit 3
+ | o 128c8 commit 2
+ |/
+ o 181cc commit 1
+ |
+ ~
+
+ $ cd ..
+
+Bookmark name appears in output
+
+ $ hg init bookmarks
+ $ cd bookmarks
+ $ echo 0 > foo
+ $ hg -q commit -A -m 'commit 0'
+ $ echo 1 > foo
+ $ hg commit -m 'commit 1'
+ $ echo 2 > foo
+ $ hg commit -m 'commit 2'
+ $ hg phase --public -r .
+ $ hg bookmark @
+ $ hg -q up -r 1
+ $ echo 3 > foo
+ $ hg commit -m 'commit 3'
+ created new head
+ $ echo 4 > foo
+ $ hg commit -m 'commit 4'
+ $ hg bookmark mybook
+
+ $ hg show underway
+ @ cac82 (mybook) commit 4
+ o f0abc commit 3
+ | o 128c8 (@) commit 2
+ |/
+ o 181cc commit 1
+ |
+ ~
+
+ $ cd ..
--- a/tests/test-show.t Wed Apr 12 20:28:44 2017 -0700
+++ b/tests/test-show.t Wed Apr 12 20:31:15 2017 -0700
@@ -11,6 +11,7 @@
available views:
bookmarks -- bookmarks and their associated changeset
+ underway -- changesets that aren't finished
abort: no view requested
(use "hg show VIEW" to choose a view)
@@ -39,6 +40,8 @@
bookmarks bookmarks and their associated changeset
+ underway changesets that aren't finished
+
(use 'hg help -e show' to show help for the show extension)
options: