# HG changeset patch # User Gregory Szorc # Date 1492054275 25200 # Node ID 99bc93147d8749539f27fd0243a47c50f7bb9bed # Parent 3e9f118cc8347270655f4623ba8876a748b42c35 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. diff -r 3e9f118cc834 -r 99bc93147d87 hgext/show.py --- 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 `.""" @@ -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 diff -r 3e9f118cc834 -r 99bc93147d87 mercurial/templates/map-cmdline.show --- 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}' diff -r 3e9f118cc834 -r 99bc93147d87 tests/test-show-underway.t --- /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 .. diff -r 3e9f118cc834 -r 99bc93147d87 tests/test-show.t --- 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: