private void WriteBranchLabel(string id, IBranch b, IRemoteWebUrlProvider remoteUrlProvider) { IAttrSet style = _style.LabelBranch; string url = remoteUrlProvider?.GetBranchLink(b); _gvWriter.Node(id, style.Label(b.Label).Url(url)); }
private void WriteNode(INode n, IRemoteWebUrlProvider remoteUrlProvider) { string url = remoteUrlProvider?.GetCommitLink(n.Commit); string tooltip = _tooltipHelper.MakeNodeTooltip(n); IAttrSet nodeAttrs = AttrSet.Empty .Url(url) .Tooltip(tooltip); _gvWriter.Node(n.Commit, nodeAttrs); }
private void WriteBranchEndingEdge( INode pointedNode, string id, IBranch b, IRemoteWebUrlProvider remoteUrlProvider ) { IAttrSet style = _style.EdgeBranchLabel; string url = remoteUrlProvider?.GetBranchMetaLink(b); _gvWriter.Edge(pointedNode.Commit, id, style.Url(url)); }
private void WriteEdge(INode a, INode b, IRemoteWebUrlProvider remoteUrlProvider) { string url = remoteUrlProvider?.GetCompareCommitsLink(a.Commit, b.Commit); string tooltip = _tooltipHelper.MakeEdgeTooltip(a, b); IAttrSet attrSet = AttrSet.Empty .Url(url) .Tooltip(tooltip); bool hasMergedCommits = b.AbsorbedParentCommits.Any(); if (hasMergedCommits) { attrSet = attrSet.Add(_style.EdgeMergedCommits); } _gvWriter.Edge(a.Commit, b.Commit, attrSet); }
private void WriteBranchPointer(IBranch b, ITree tree, bool isLesser, IRemoteWebUrlProvider remoteUrlProvider) { INode pointedNode = tree.GetNode(b.Tip); bool isOwned = tree.GetContainingBranch(pointedNode) == b; // Ending textual node. string branchLabelId = MakeNodeIdForPointerLabel(pointedNode, b); bool shouldSink = !isLesser && isOwned; using (_gvWriter.StartSubGraph()) { if (shouldSink) { _gvWriter.RawAttributes(AttrSet.Empty.Rank(RankType.Sink)); } WriteBranchLabel(branchLabelId, b, remoteUrlProvider); } WriteBranchEndingEdge(pointedNode, branchLabelId, b, remoteUrlProvider); }
public void Render( ITree tree, IRemote usedRemote, IBranchesKnowledge branchesKnowledge, ITreeRenderingOptions options) { IRemoteWebUrlProvider remoteUrlProvider = _remoteWebUrlProviderFactory.CreateUrlProvider(usedRemote.Url, options.ForceTreatAsGitHub); WriteHeader(); IBranch[] branchesWithNodes = tree.Branches.Where(b => tree.EnumerateNodes(b).Any()).ToArray(); IBranch[] currentBranchesSorted = OrderByFirstCommitDate(branchesWithNodes, tree).ToArray(); IPairList <INode, INode> unwrittenMerges = new PairList <INode, INode>(); IPairList <INode, INode> writtenMerges = new PairList <INode, INode>(); // Main branches. foreach (IBranch b in currentBranchesSorted) { _gvWriter.EmptyLine(); _gvWriter.Comment($"Branch {b.Label}."); using (_gvWriter.StartSubGraph()) { _gvWriter.SetNodeAttributes(AttrSet.Empty.Group(b.Label)); Color drawColor = branchesKnowledge.GetSuggestedDrawingColorFor(b); bool isLesser = branchesKnowledge.IsAWorkItemBranch(b); IAttrSet nodeStyle = _style.GetBranchNodeStyle(drawColor, isLesser); IAttrSet edgeStyle = _style.GetBranchEdgeStyle(drawColor, isLesser); _gvWriter.SetNodeAttributes(nodeStyle); _gvWriter.SetEdgeAttributes(edgeStyle); INode[] nodes = tree.EnumerateNodes(b).ToArray(); for (int i = 0; i < nodes.Length; i++) { INode currentNode = nodes[i]; WriteNode(currentNode, remoteUrlProvider); if (i == 0) { // Starting node. INode parent = currentNode.Parents.FirstOrDefault(); bool hasParent = parent != null; if (!hasParent) { _gvWriter.Comment("Starting line."); string id = string.Format($"{currentNode.Commit.Treeish}_start"); // Write starting empty node. using (_gvWriter.StartSubGraph()) { _gvWriter.RawAttributes(AttrSet.Empty.Rank(RankType.Source)); _gvWriter.Node(id, AttrSet.Empty.Width(0).Height(0).PenWidth(0)); } _gvWriter.Edge(id, currentNode.Commit, _style.EdgeBranchStartVirtual); _gvWriter.EmptyLine(); } else { // It is some other branch, and we draw that edge. WriteEdge(parent, currentNode, remoteUrlProvider); writtenMerges.Add(parent, currentNode); } } bool isLast = i == nodes.Length - 1; INode nextNode = isLast ? null : nodes[i + 1]; if (!isLast) { // Edge to the next node. WriteEdge(currentNode, nextNode, remoteUrlProvider); } else { WriteBranchPointer(b, tree, isLesser, remoteUrlProvider); } INode[] otherChildren = currentNode.Children.Except(nextNode).ToArray(); foreach (INode child in otherChildren) { unwrittenMerges.Add(currentNode, child); } } } } IBranch[] branchesWithoutNodes = tree.Branches.Except(branchesWithNodes).ToArray(); foreach (IBranch b in branchesWithoutNodes) { bool isLesser = branchesKnowledge.IsAWorkItemBranch(b); WriteBranchPointer(b, tree, isLesser, remoteUrlProvider); } // Tags. ITag[] tags = tree.Tags.ToArray(); foreach (ITag t in tags) { _gvWriter.EmptyLine(); INode n = tree.GetNode(t.Tip); string id = MakeNodeIdForPointerLabel(n, t); using (_gvWriter.StartSubGraph()) { _gvWriter.Comment($"Tag {t.Label}."); _gvWriter.RawAttributes(AttrSet.Empty.Rank(RankType.Same)); string url = remoteUrlProvider?.GetTagLink(t); _gvWriter.Node(id, _style.LabelTag.Label(t.Label).Url(url)); _gvWriter.Edge(n.Commit, id, _style.EdgeTagLabel); } } INode[] allLeftOvers = tree.Nodes.Where(n => tree.GetContainingBranch(n) == null).ToArray(); if (allLeftOvers.Length > 0) { using (_gvWriter.StartSubGraph()) { _gvWriter.EmptyLine(); _gvWriter.Comment("Leftover nodes."); _gvWriter.SetNodeAttributes(_style.NodeOrphaned); foreach (INode currentNode in allLeftOvers) { WriteNode(currentNode, remoteUrlProvider); // Remember children. foreach (INode child in currentNode.Children) { unwrittenMerges.Add(currentNode, child); } } } } PairList <INode, INode> edgesToWrite = unwrittenMerges.Except(writtenMerges).ToPairList(); if (edgesToWrite.Count > 0) { using (_gvWriter.StartSubGraph()) { _gvWriter.EmptyLine(); _gvWriter.Comment("Other edges."); _gvWriter.SetEdgeAttributes(_style.EdgeOther); foreach (Tuple <INode, INode> edge in edgesToWrite) { _gvWriter.Edge(edge.Item1.Commit, edge.Item2.Commit); } } } WriteFooter(); }