Mercurial > public > mercurial-scm > hg
diff hgext/graphlog.py @ 17179:0849d725e2f9
graphlog: extract ascii drawing code into graphmod
author | Patrick Mezard <patrick@mezard.eu> |
---|---|
date | Wed, 11 Jul 2012 17:13:39 +0200 |
parents | 8299a9ad48dd |
children | ae0629161090 |
line wrap: on
line diff
--- a/hgext/graphlog.py Sun Jun 24 18:11:52 2012 +0200 +++ b/hgext/graphlog.py Wed Jul 11 17:13:39 2012 +0200 @@ -21,209 +21,6 @@ command = cmdutil.command(cmdtable) testedwith = 'internal' -def asciiedges(type, char, lines, seen, rev, parents): - """adds edge info to changelog DAG walk suitable for ascii()""" - if rev not in seen: - seen.append(rev) - nodeidx = seen.index(rev) - - knownparents = [] - newparents = [] - for parent in parents: - if parent in seen: - knownparents.append(parent) - else: - newparents.append(parent) - - ncols = len(seen) - nextseen = seen[:] - nextseen[nodeidx:nodeidx + 1] = newparents - edges = [(nodeidx, nextseen.index(p)) for p in knownparents] - - while len(newparents) > 2: - # ascii() only knows how to add or remove a single column between two - # calls. Nodes with more than two parents break this constraint so we - # introduce intermediate expansion lines to grow the active node list - # slowly. - edges.append((nodeidx, nodeidx)) - edges.append((nodeidx, nodeidx + 1)) - nmorecols = 1 - yield (type, char, lines, (nodeidx, edges, ncols, nmorecols)) - char = '\\' - lines = [] - nodeidx += 1 - ncols += 1 - edges = [] - del newparents[0] - - if len(newparents) > 0: - edges.append((nodeidx, nodeidx)) - if len(newparents) > 1: - edges.append((nodeidx, nodeidx + 1)) - nmorecols = len(nextseen) - ncols - seen[:] = nextseen - yield (type, char, lines, (nodeidx, edges, ncols, nmorecols)) - -def _fixlongrightedges(edges): - for (i, (start, end)) in enumerate(edges): - if end > start: - edges[i] = (start, end + 1) - -def _getnodelineedgestail( - node_index, p_node_index, n_columns, n_columns_diff, p_diff, fix_tail): - if fix_tail and n_columns_diff == p_diff and n_columns_diff != 0: - # Still going in the same non-vertical direction. - if n_columns_diff == -1: - start = max(node_index + 1, p_node_index) - tail = ["|", " "] * (start - node_index - 1) - tail.extend(["/", " "] * (n_columns - start)) - return tail - else: - return ["\\", " "] * (n_columns - node_index - 1) - else: - return ["|", " "] * (n_columns - node_index - 1) - -def _drawedges(edges, nodeline, interline): - for (start, end) in edges: - if start == end + 1: - interline[2 * end + 1] = "/" - elif start == end - 1: - interline[2 * start + 1] = "\\" - elif start == end: - interline[2 * start] = "|" - else: - if 2 * end >= len(nodeline): - continue - nodeline[2 * end] = "+" - if start > end: - (start, end) = (end, start) - for i in range(2 * start + 1, 2 * end): - if nodeline[i] != "+": - nodeline[i] = "-" - -def _getpaddingline(ni, n_columns, edges): - line = [] - line.extend(["|", " "] * ni) - if (ni, ni - 1) in edges or (ni, ni) in edges: - # (ni, ni - 1) (ni, ni) - # | | | | | | | | - # +---o | | o---+ - # | | c | | c | | - # | |/ / | |/ / - # | | | | | | - c = "|" - else: - c = " " - line.extend([c, " "]) - line.extend(["|", " "] * (n_columns - ni - 1)) - return line - -def asciistate(): - """returns the initial value for the "state" argument to ascii()""" - return [0, 0] - -def ascii(ui, state, type, char, text, coldata): - """prints an ASCII graph of the DAG - - takes the following arguments (one call per node in the graph): - - - ui to write to - - Somewhere to keep the needed state in (init to asciistate()) - - Column of the current node in the set of ongoing edges. - - Type indicator of node data, usually 'C' for changesets. - - Payload: (char, lines): - - Character to use as node's symbol. - - List of lines to display as the node's text. - - Edges; a list of (col, next_col) indicating the edges between - the current node and its parents. - - Number of columns (ongoing edges) in the current revision. - - The difference between the number of columns (ongoing edges) - in the next revision and the number of columns (ongoing edges) - in the current revision. That is: -1 means one column removed; - 0 means no columns added or removed; 1 means one column added. - """ - - idx, edges, ncols, coldiff = coldata - assert -2 < coldiff < 2 - if coldiff == -1: - # Transform - # - # | | | | | | - # o | | into o---+ - # |X / |/ / - # | | | | - _fixlongrightedges(edges) - - # add_padding_line says whether to rewrite - # - # | | | | | | | | - # | o---+ into | o---+ - # | / / | | | # <--- padding line - # o | | | / / - # o | | - add_padding_line = (len(text) > 2 and coldiff == -1 and - [x for (x, y) in edges if x + 1 < y]) - - # fix_nodeline_tail says whether to rewrite - # - # | | o | | | | o | | - # | | |/ / | | |/ / - # | o | | into | o / / # <--- fixed nodeline tail - # | |/ / | |/ / - # o | | o | | - fix_nodeline_tail = len(text) <= 2 and not add_padding_line - - # nodeline is the line containing the node character (typically o) - nodeline = ["|", " "] * idx - nodeline.extend([char, " "]) - - nodeline.extend( - _getnodelineedgestail(idx, state[1], ncols, coldiff, - state[0], fix_nodeline_tail)) - - # shift_interline is the line containing the non-vertical - # edges between this entry and the next - shift_interline = ["|", " "] * idx - if coldiff == -1: - n_spaces = 1 - edge_ch = "/" - elif coldiff == 0: - n_spaces = 2 - edge_ch = "|" - else: - n_spaces = 3 - edge_ch = "\\" - shift_interline.extend(n_spaces * [" "]) - shift_interline.extend([edge_ch, " "] * (ncols - idx - 1)) - - # draw edges from the current node to its parents - _drawedges(edges, nodeline, shift_interline) - - # lines is the list of all graph lines to print - lines = [nodeline] - if add_padding_line: - lines.append(_getpaddingline(idx, ncols, edges)) - lines.append(shift_interline) - - # make sure that there are as many graph lines as there are - # log strings - while len(text) < len(lines): - text.append("") - if len(lines) < len(text): - extra_interline = ["|", " "] * (ncols + coldiff) - while len(lines) < len(text): - lines.append(extra_interline) - - # print lines - indentation_level = max(ncols, ncols + coldiff) - for (line, logstr) in zip(lines, text): - ln = "%-*s %s" % (2 * indentation_level, "".join(line), logstr) - ui.write(ln.rstrip() + '\n') - - # ... and start over - state[0] = coldiff - state[1] = idx - def _checkunsupportedflags(pats, opts): for op in ["newest_first"]: if op in opts and opts[op]: @@ -441,7 +238,7 @@ def generate(ui, dag, displayer, showparents, edgefn, getrenamed=None, filematcher=None): - seen, state = [], asciistate() + seen, state = [], graphmod.asciistate() for rev, type, ctx, parents in dag: char = 'o' if ctx.node() in showparents: @@ -465,7 +262,7 @@ displayer.flush(rev) edges = edgefn(type, char, lines, seen, rev, parents) for type, char, lines, coldata in edges: - ascii(ui, state, type, char, lines, coldata) + graphmod.ascii(ui, state, type, char, lines, coldata) displayer.close() @command('glog', @@ -516,8 +313,8 @@ getrenamed = templatekw.getrenamedfn(repo, endrev=endrev) displayer = show_changeset(ui, repo, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] - generate(ui, revdag, displayer, showparents, asciiedges, getrenamed, - filematcher) + generate(ui, revdag, displayer, showparents, graphmod.asciiedges, + getrenamed, filematcher) def graphrevs(repo, nodes, opts): limit = cmdutil.loglimit(opts) @@ -544,7 +341,7 @@ revdag = graphrevs(repo, o, opts) displayer = show_changeset(ui, repo, opts, buffered=True) showparents = [ctx.node() for ctx in repo[None].parents()] - generate(ui, revdag, displayer, showparents, asciiedges) + generate(ui, revdag, displayer, showparents, graphmod.asciiedges) def gincoming(ui, repo, source="default", **opts): """show the incoming changesets alongside an ASCII revision graph @@ -562,7 +359,7 @@ def display(other, chlist, displayer): revdag = graphrevs(other, chlist, opts) showparents = [ctx.node() for ctx in repo[None].parents()] - generate(ui, revdag, displayer, showparents, asciiedges) + generate(ui, revdag, displayer, showparents, graphmod.asciiedges) hg._incoming(display, subreporecurse, ui, repo, source, opts, buffered=True)