diff --git a/hgext/show.py b/hgext/show.py --- a/hgext/show.py +++ b/hgext/show.py @@ -397,7 +397,8 @@ revdag = graphmod.dagwalker(repo, revs) ui.setconfig('experimental', 'graphshorten', True) - cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges) + cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, + widthfn=graphmod.asciiwidth) def extsetup(ui): # Alias `hg ` to `hg show `. diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -2508,7 +2508,7 @@ return formatnode def displaygraph(ui, repo, dag, displayer, edgefn, getrenamed=None, - filematcher=None): + filematcher=None, widthfn=None): formatnode = _graphnodeformatter(ui, displayer) state = graphmod.asciistate() styles = state['styles'] @@ -2545,7 +2545,11 @@ revmatchfn = None if filematcher is not None: revmatchfn = filematcher(ctx.rev()) - displayer.show(ctx, copies=copies, matchfn=revmatchfn) + graphwidth = 0 + if widthfn: + graphwidth = widthfn(state, rev, parents) + displayer.show(ctx, copies=copies, matchfn=revmatchfn, + _graphwidth=graphwidth) lines = displayer.hunk.pop(rev).split('\n') if not lines[-1]: del lines[-1] @@ -2570,7 +2574,7 @@ ui.pager('log') displayer = show_changeset(ui, repo, opts, buffered=True) displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed, - filematcher) + filematcher, widthfn=graphmod.asciiwidth) def checkunsupportedgraphflags(pats, opts): for op in ["newest_first"]: diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -3123,7 +3123,8 @@ def display(other, chlist, displayer): revdag = cmdutil.graphrevs(other, chlist, opts) cmdutil.displaygraph(ui, repo, revdag, displayer, - graphmod.asciiedges) + graphmod.asciiedges, + widthfn=graphmod.asciiwidth) hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True) return 0 @@ -3572,7 +3573,8 @@ revdag = cmdutil.graphrevs(repo, o, opts) ui.pager('outgoing') displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True) - cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges) + cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, + widthfn=graphmod.asciiwidth) cmdutil.outgoinghooks(ui, repo, other, opts, o) return 0 diff --git a/mercurial/graphmod.py b/mercurial/graphmod.py --- a/mercurial/graphmod.py +++ b/mercurial/graphmod.py @@ -222,6 +222,24 @@ state['edges'].pop(rev, None) yield (type, char, lines, (nodeidx, edges, ncols, nmorecols)) +def asciiwidth(state, rev, parents): + """returns the width of the graph drawn by ascii() based on asciiedges()""" + seen = state['seen'][:] + if rev not in seen: + seen.append(rev) + columns = len(seen) + + # We might be adding columns to handle previously unseen parents, but only + # one of them goes into the graph width for this rev. + newparents = 0 + for ptype, parent in parents: + if parent != rev and parent not in seen: + newparents += 1 + columns = max(columns, columns + min(2, newparents) - 1) + + # Each column is 2 characters, and there's another character of padding. + return 1 + 2 * columns + def _fixlongrightedges(edges): for (i, (start, end)) in enumerate(edges): if end > start: diff --git a/mercurial/templatekw.py b/mercurial/templatekw.py --- a/mercurial/templatekw.py +++ b/mercurial/templatekw.py @@ -764,6 +764,13 @@ """Integer. The width of the current terminal.""" return repo.ui.termwidth() +@templatekeyword('graphwidth') +def graphwidth(repo, ctx, templ, **args): + """Integer. The width of the graph drawn by 'log --graph' or zero.""" + # The value args['graphwidth'] will be this function, so we use an internal + # name to pass the value through props into this function. + return args.get('_graphwidth', 0) + @templatekeyword('troubles') def showtroubles(**args): """List of strings. Evolution troubles affecting the changeset. diff --git a/tests/test-command-template.t b/tests/test-command-template.t --- a/tests/test-command-template.t +++ b/tests/test-command-template.t @@ -4319,3 +4319,155 @@ custom $ cd .. + +Test 'graphwidth' in 'hg log' on various topologies. The key here is that the +printed graphwidths 3, 5, 7, etc. should all line up in their respective +columns. We don't care about other aspects of the graph rendering here. + + $ hg init graphwidth + $ cd graphwidth + + $ wrappabletext="a a a a a a a a a a a a" + + $ printf "first\n" > file + $ hg add file + $ hg commit -m "$wrappabletext" + + $ printf "first\nsecond\n" > file + $ hg commit -m "$wrappabletext" + + $ hg checkout 0 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ printf "third\nfirst\n" > file + $ hg commit -m "$wrappabletext" + created new head + + $ hg merge + merging file + 0 files updated, 1 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + + $ hg log --graph -T "{graphwidth}" + @ 3 + | + | @ 5 + |/ + o 3 + + $ hg commit -m "$wrappabletext" + + $ hg log --graph -T "{graphwidth}" + @ 5 + |\ + | o 5 + | | + o | 5 + |/ + o 3 + + + $ hg checkout 0 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ printf "third\nfirst\nsecond\n" > file + $ hg commit -m "$wrappabletext" + created new head + + $ hg log --graph -T "{graphwidth}" + @ 3 + | + | o 7 + | |\ + +---o 7 + | | + | o 5 + |/ + o 3 + + + $ hg log --graph -T "{graphwidth}" -r 3 + o 5 + |\ + ~ ~ + + $ hg log --graph -T "{graphwidth}" -r 1 + o 3 + | + ~ + + $ hg merge + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + $ hg commit -m "$wrappabletext" + + $ printf "seventh\n" >> file + $ hg commit -m "$wrappabletext" + + $ hg log --graph -T "{graphwidth}" + @ 3 + | + o 5 + |\ + | o 5 + | | + o | 7 + |\ \ + | o | 7 + | |/ + o / 5 + |/ + o 3 + + +The point of graphwidth is to allow wrapping that accounts for the space taken +by the graph. + + $ COLUMNS=10 hg log --graph -T "{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 + | o 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 + | o | 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 + o a a a a + a a a a + a a a a + +Something tricky happens when there are elided nodes; the next drawn row of +edges can be more than one column wider, but the graph width only increases by +one column. The remaining columns are added in between the nodes. + + $ hg log --graph -T "{graphwidth}" -r "0|2|4|5" + o 5 + |\ + | \ + | :\ + o : : 7 + :/ / + : o 5 + :/ + o 3 + + + $ cd .. +