# HG changeset patch # User Anton Shestakov # Date 1513687285 -28800 # Node ID baca93a47992fc2ec1aa6d255764793f7df03966 # Parent bdae51a83dfb8d2a941ff8945287ba7a182298bc hgweb: make different kinds of commits look differently on /graph Regular hg log -G uses different symbols for some graph nodes, such as commits that close branches and hidden commits. It also marks the currently checked out commit with "@". Since hg serve is sometimes used/recommended as a more visual alternative to CLI, it makes sense to port these features to hgweb. "graphnode" includes the style of a particular node and also if it's currently checked out or not, both at the same time. This is different from hg log -G (which uses templatekw.showgraphnode), where there's only place for one character, but hgweb doesn't have this limitation, since it uses and not plain text. I'm using one string of 1 or 2 characters in this patch, it's not the most self-explanatory format, but it's concise, uses the same characters as hg log -G, and is internal to hgweb (i.e. not used for json-graph). I'm more or less fine with how things look visually, but there's still room for improvement. Feel free to criticise or point me to good-looking graphs of this kind for inspiration. diff -r bdae51a83dfb -r baca93a47992 mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py Thu Dec 21 13:58:11 2017 +0100 +++ b/mercurial/hgweb/webcommands.py Tue Dec 19 20:41:25 2017 +0800 @@ -13,7 +13,7 @@ import re from ..i18n import _ -from ..node import hex, short +from ..node import hex, nullid, short from .common import ( ErrorResponse, @@ -1248,6 +1248,24 @@ tree = list(item for item in graphmod.colored(dag, web.repo) if item[1] == graphmod.CHANGESET) + def nodecurrent(ctx): + wpnodes = web.repo.dirstate.parents() + if wpnodes[1] == nullid: + wpnodes = wpnodes[:1] + if ctx.node() in wpnodes: + return '@' + return '' + + def nodesymbol(ctx): + if ctx.obsolete(): + return 'x' + elif ctx.isunstable(): + return '*' + elif ctx.closesbranch(): + return '_' + else: + return 'o' + def fulltree(): pos = web.repo[graphtop].rev() tree = [] @@ -1260,6 +1278,7 @@ def jsdata(): return [{'node': pycompat.bytestr(ctx), + 'graphnode': nodecurrent(ctx) + nodesymbol(ctx), 'vertex': vtx, 'edges': edges} for (id, type, ctx, vtx, edges) in fulltree()] diff -r bdae51a83dfb -r baca93a47992 mercurial/templates/static/mercurial.js --- a/mercurial/templates/static/mercurial.js Thu Dec 21 13:58:11 2017 +0100 +++ b/mercurial/templates/static/mercurial.js Tue Dec 19 20:41:25 2017 +0800 @@ -90,11 +90,68 @@ }, - vertex: function(x, y, radius, color, parity, cur) { + graphNodeCurrent: function(x, y, radius) { + this.ctx.lineWidth = 2; + this.ctx.beginPath(); + this.ctx.arc(x, y, radius * 1.75, 0, Math.PI * 2, true); + this.ctx.stroke(); + }, + + graphNodeClosing: function(x, y, radius) { + this.ctx.fillRect(x - radius, y - 1.5, radius * 2, 3); + }, + + graphNodeUnstable: function(x, y, radius) { + var x30 = radius * Math.cos(Math.PI / 6); + var y30 = radius * Math.sin(Math.PI / 6); + this.ctx.lineWidth = 2; this.ctx.beginPath(); - this.setColor(color, 0.25, 0.75); + this.ctx.moveTo(x, y - radius); + this.ctx.lineTo(x, y + radius); + this.ctx.moveTo(x - x30, y - y30); + this.ctx.lineTo(x + x30, y + y30); + this.ctx.moveTo(x - x30, y + y30); + this.ctx.lineTo(x + x30, y - y30); + this.ctx.stroke(); + }, + + graphNodeObsolete: function(x, y, radius) { + var p45 = radius * Math.cos(Math.PI / 4); + this.ctx.lineWidth = 3; + this.ctx.beginPath(); + this.ctx.moveTo(x - p45, y - p45); + this.ctx.lineTo(x + p45, y + p45); + this.ctx.moveTo(x - p45, y + p45); + this.ctx.lineTo(x + p45, y - p45); + this.ctx.stroke(); + }, + + graphNodeNormal: function(x, y, radius) { + this.ctx.beginPath(); this.ctx.arc(x, y, radius, 0, Math.PI * 2, true); this.ctx.fill(); + }, + + vertex: function(x, y, radius, color, parity, cur) { + this.ctx.save(); + this.setColor(color, 0.25, 0.75); + if (cur.graphnode[0] === '@') { + this.graphNodeCurrent(x, y, radius); + } + switch (cur.graphnode.substr(-1)) { + case '_': + this.graphNodeClosing(x, y, radius); + break; + case '*': + this.graphNodeUnstable(x, y, radius); + break; + case 'x': + this.graphNodeObsolete(x, y, radius); + break; + default: + this.graphNodeNormal(x, y, radius); + } + this.ctx.restore(); var left = (this.bg_height - this.box_size) + (this.columns + 1) * this.box_size; var item = document.querySelector('[data-node="' + cur.node + '"]'); diff -r bdae51a83dfb -r baca93a47992 tests/test-hgweb-commands.t --- a/tests/test-hgweb-commands.t Thu Dec 21 13:58:11 2017 +0100 +++ b/tests/test-hgweb-commands.t Tue Dec 19 20:41:25 2017 +0800 @@ -1822,7 +1822,7 @@