/// <summary> /// Renders an arrow between two participants. /// </summary> /// <remarks> /// Takes scope (if/alt/group/etc.) into account for correctly close activation lines. /// </remarks> private static void RenderArrow(StringBuilder stringBuilder, Arrow arrow, IReadOnlyList <InteractionFragment> scope, Interactions tree, List <string> activations) { var target = (arrow.Source != "W" && arrow.Target == "A") ? "Q" : arrow.Target; stringBuilder.Arrow(arrow.Source, $"-{arrow.Color}>", target, label: arrow.Name); if (!activations.Contains(arrow.Source)) { // Scope was activated in current scope if (arrow.Target != "]" && arrow.Source != "A" && arrow.Source != "W" && !arrow.Source.StartsWith("x ", StringComparison.Ordinal) && scope.Descendants <Arrow>().Last(a => a.Source == arrow.Source) == arrow && arrow.Source != arrow.Target) { // This is the last arrow from this source stringBuilder.Deactivate(arrow.Source); activations.Remove(arrow.Source); } } if (!activations.Contains(arrow.Target)) { // Scope was not activated by the parent scope if ((arrow.Target != "A" || arrow.Source == "W") && arrow.Target != "Q" && arrow.Target != "W" && !arrow.Target.StartsWith("x ", StringComparison.Ordinal) && arrow.Source != arrow.Target && scope.OfType <Arrow>().First(a => a.Target == arrow.Target) == arrow) { var previousArrows = arrow.Ancestors().SelectMany(a => a.StatementsBeforeSelf()).OfType <Arrow>().ToList(); if (!previousArrows.Any(a => a.Target == arrow.Target) && !ExternalTargets.Contains(arrow.Target)) { // There was no earlier activation in the current scope stringBuilder.Activate(arrow.Target); activations.Add(arrow.Target); } } } }