private void CreateBlockAdornments()

in src/Structure/StructureVisualizer/StructureAdornmentManager.cs [210:316]


        private void CreateBlockAdornments(IMappingTagSpan<IBlockTag> tag, NormalizedSnapshotSpanCollection newOrReformattedSpans, double left, double right)
        {
            NormalizedSnapshotSpanCollection spans = tag.Span.GetSpans(_view.TextSnapshot);
            if (spans.Count > 0)
            {
                //Get the start of the tag's span (which could be out of the view or not even mappable to
                //the view's text snapshot).
                var statementStart = _view.BufferGraph.MapUpToSnapshot(tag.Tag.StatementStart, PointTrackingMode.Positive, PositionAffinity.Predecessor, _view.TextSnapshot);
                if (statementStart.HasValue)
                {
                    var end = _view.BufferGraph.MapUpToSnapshot(tag.Tag.Span.End, PointTrackingMode.Positive, PositionAffinity.Predecessor, _view.TextSnapshot);
                    if (end.HasValue)
                    {
                        //Get the full extent of the block tag so that its adornments will be destroyed if anything in the block changes.
                        SnapshotSpan extent = new SnapshotSpan(statementStart.Value, end.Value);

                        bool intersecting = newOrReformattedSpans.IntersectsWith(new NormalizedSnapshotSpanCollection(extent));
                        if (intersecting)
                        {
                            var start = _view.BufferGraph.MapUpToSnapshot(tag.Tag.Span.Start, PointTrackingMode.Positive, PositionAffinity.Predecessor, _view.TextSnapshot);
                            if (start.HasValue)
                            {
                                ITextSnapshotLine startLine = start.Value.GetContainingLine();

                                if (_showAdornments)
                                {
                                    double x = -1.0;
                                    foreach (var span in spans)
                                    {
                                        if (span.OverlapsWith(_view.TextViewLines.FormattedSpan))
                                        {
                                            ITextViewLine spanTop = _view.TextViewLines.GetTextViewLineContainingBufferPosition(span.Start);
                                            double yTop = (spanTop == null) ? _view.TextViewLines.FirstVisibleLine.Top : spanTop.Bottom;

                                            ITextViewLine spanBottom = _view.TextViewLines.GetTextViewLineContainingBufferPosition(span.End);
                                            double yBottom = (spanBottom == null) ? _view.TextViewLines.LastVisibleLine.Bottom : spanBottom.Top;

                                            if (yBottom > yTop)
                                            {
                                                if (x < 0.0)
                                                {
                                                    //We have a starting point ... but it may be the wrong one. We have three cases to consider:
                                                    //1)        if (foo) {
                                                    //          |                               //Line goes here
                                                    //
                                                    //2)        if (foo)
                                                    //              {
                                                    //              |                           //Line goes here
                                                    //
                                                    //3)        if (bar &&
                                                    //              foo) {
                                                    //          |                               //Line goes here
                                                    //
                                                    //
                                                    //In each of these cases, we need to find the position of the first non-whitespace character on the line
                                                    SnapshotPoint blockStart = FindFirstNonwhitespace(startLine);

                                                    //If the span start's on the first non-whitespace character of the line, then we have case 2
                                                    //(& we're done).
                                                    if (blockStart != start.Value)
                                                    {
                                                        //Case 1 or 3 ... see if the start & statement start are on the same line.
                                                        //Is the span start on the same line as the statement start (if so, we have case 1 & are done).
                                                        if (!startLine.Extent.Contains(statementStart.Value))
                                                        {
                                                            //Case 3.
                                                            blockStart = statementStart.Value;
                                                        }
                                                    }

                                                    //Get the x-coordinate of the adornment == middle of the character that starts the block.
                                                    ITextViewLine tagTop = _view.GetTextViewLineContainingBufferPosition(blockStart);
                                                    TextBounds bounds = tagTop.GetCharacterBounds(blockStart);
                                                    x = Math.Floor((bounds.Left + bounds.Right) * 0.5);   //Make sure this is only a pixel wide.
                                                }

                                                this.CreateBlockAdornment(tag.Tag, extent, x, yTop, yBottom);
                                            }
                                        }
                                    }
                                }

                                if (_showMethodSeparator && (tag.Tag.Type == BlockType.Method) && (startLine.End < end.Value))
                                {
                                    var point = _view.BufferGraph.MapUpToBuffer(end.Value, PointTrackingMode.Negative, PositionAffinity.Predecessor, _view.VisualSnapshot.TextBuffer);
                                    if (point.HasValue)
                                    {
                                        ITextViewLine spanBottom = _view.TextViewLines.GetTextViewLineContainingBufferPosition(end.Value);
                                        if (spanBottom != null)
                                        {
                                            GeometryAdornment adornment = new GeometryAdornment(_coloring.MethodSeparatorAndHighlightColoring.LineBrush,
                                                                                                new RectangleGeometry(new Rect(0.0, 0.0, right - left, 1.0)));

                                            Canvas.SetLeft(adornment, left);
                                            Canvas.SetTop(adornment, spanBottom.Bottom - 1.0);

                                            _methodSeparators.Add(adornment);
                                            _layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, extent, adornment, adornment, OnMethodSeparatorRemoved);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }