in src/MatchMargin/MatchMarginElement.cs [294:390]
private void RedrawAdornments(IList<ITextViewLine> newOrReformattedLines, double viewportLeft, double viewportRight)
{
if (_areAdornmentsEnabled)
{
if ((newOrReformattedLines == null) || (viewportLeft < _left) || (viewportRight > _right))
{
_left = viewportLeft - 50.0; //Add in a little padding so small scrolls won't trigger a refresh.
_right = viewportRight + 50.0;
_layer.RemoveAllAdornments();
newOrReformattedLines = _textView.TextViewLines;
}
if ((_highlight != null) && (_search != null))
{
//Take a snapshot of the matches found to date (this could still be changing
//if the search has not completed yet).
IList<SnapshotSpan> matches = _search.Matches;
if ((matches.Count > 0) && (matches[0].Snapshot == _textView.TextSnapshot))
{
//matches is sorted, as is newOrReformattedLines (as are the spans in visibleText), so keep track of the last match found since it
//is a good starting point for the next match.
int firstLegalMatch = 0;
int caretPosition = _textView.Caret.Position.BufferPosition;
foreach (var line in newOrReformattedLines)
{
//Find all matches on the visible text in line.
if (line.TextRight > _left)
{
SnapshotPoint? leftCharacter = line.GetBufferPositionFromXCoordinate(_left);
if (!leftCharacter.HasValue)
leftCharacter = line.Start;
SnapshotPoint? rightCharacter = line.GetBufferPositionFromXCoordinate(_right);
if (!rightCharacter.HasValue)
rightCharacter = line.End;
if (leftCharacter.Value.Position > rightCharacter.Value.Position)
{
// Swap left & right (due to bidi sequences, we could end up with left coming after right in the buffer)
var t = leftCharacter;
leftCharacter = rightCharacter;
rightCharacter = t;
}
//We know the start & endpoints exist, the edit & visual snapshots represent the same instant and we're mapping up so just map up
SnapshotPoint leftInVisualBuffer = _textView.TextViewModel.GetNearestPointInVisualSnapshot(leftCharacter.Value, _textView.VisualSnapshot, PointTrackingMode.Negative);
SnapshotPoint rightInVisualBuffer = _textView.TextViewModel.GetNearestPointInVisualSnapshot(rightCharacter.Value, _textView.VisualSnapshot, PointTrackingMode.Negative);
NormalizedSnapshotSpanCollection visibleText = _textView.BufferGraph.MapDownToSnapshot(new SnapshotSpan(leftInVisualBuffer, rightInVisualBuffer),
SpanTrackingMode.EdgeInclusive, _textView.TextSnapshot);
foreach (var span in visibleText)
{
while (true)
{
firstLegalMatch = FindMatchIndex(matches, span.Start, firstLegalMatch);
if (firstLegalMatch >= matches.Count)
{
//No more matches, we might as well stop.
return;
}
SnapshotSpan matchingSpan = matches[firstLegalMatch];
if (matchingSpan.Start <= span.End)
{
++firstLegalMatch; //Make sure we don't redraw this adornment.
//Don't draw the adornment for the word the caret is adjacent to.
if ((caretPosition < matchingSpan.Start) || (caretPosition > matchingSpan.End))
{
Geometry g = _textView.TextViewLines.GetMarkerGeometry(matchingSpan);
if (g != null)
{
_layer.AddAdornment(matchingSpan, null, new GeometryAdornment(_adornmentMatchBrush, g));
}
}
}
else
break; //No matches in this span.
}
}
}
}
}
}
}
else
{
_layer.RemoveAllAdornments();
_left = double.MaxValue; //reset the left/right bounds so we'll redraw when options are turned back on.
_right = double.MinValue;
}
}