public override HexAndAdornmentCollection CreateHexAndAdornmentCollection(HexBufferLine line) { if (line == null) { throw new ArgumentNullException(nameof(line)); } if (line.Buffer != hexView.Buffer) { throw new ArgumentException(); } var lineSpan = line.TextSpan; List <AdornmentElementAndSpan> adornmentList = null; foreach (var tagSpan in hexTagAggregator.GetAllTags(new HexTaggerContext(line, lineSpan))) { if (adornmentList == null) { adornmentList = new List <AdornmentElementAndSpan>(); } adornmentList.Add(new AdornmentElementAndSpan(new HexAdornmentElementImpl(tagSpan), tagSpan.Span)); } // Common case if (adornmentList == null) { var elem = new HexSequenceElementImpl(lineSpan); return(new HexAndAdornmentCollectionImpl(this, new[] { elem })); } var sequenceList = new List <HexSequenceElement>(); adornmentList.Sort(AdornmentElementAndSpanComparer.Instance); int start = lineSpan.Start; int end = lineSpan.End; int curr = start; AdornmentElementAndSpan?lastAddedAdornment = null; for (int i = 0; i < adornmentList.Count; i++) { var info = adornmentList[i]; int spanStart = info.Span.Length == 0 && info.AdornmentElement.Affinity == VST.PositionAffinity.Predecessor ? info.Span.Start - 1 : info.Span.Start; if (spanStart < start) { continue; } if (info.Span.Start > end) { break; } var textSpan = VST.Span.FromBounds(curr, info.Span.Start); if (!textSpan.IsEmpty) { sequenceList.Add(new HexSequenceElementImpl(textSpan)); } if (info.Span.Start != end || (info.Span.Length == 0 && info.AdornmentElement.Affinity == VST.PositionAffinity.Predecessor)) { bool canAppend = true; if (lastAddedAdornment != null && lastAddedAdornment.Value.Span.End > info.Span.Start) { canAppend = false; } if (canAppend) { sequenceList.Add(info.AdornmentElement); lastAddedAdornment = info; } } curr = info.Span.End; } if (curr < end) { var textSpan = VST.Span.FromBounds(curr, end); Debug.Assert(!textSpan.IsEmpty); sequenceList.Add(new HexSequenceElementImpl(textSpan)); } return(new HexAndAdornmentCollectionImpl(this, sequenceList.ToArray())); }
void GetClassificationSpansCore(List <HexClassificationSpan> result, HexClassificationContext context, CancellationToken?cancellationToken) { if (context.IsDefault) { throw new ArgumentException(); } var textSpan = context.LineSpan; var list = new List <HexClassificationSpan>(); var taggerContext = new HexTaggerContext(context.Line, context.LineSpan); var tags = cancellationToken != null?hexTagAggregator.GetAllTags(taggerContext, cancellationToken.Value) : hexTagAggregator.GetAllTags(taggerContext); foreach (var tagSpan in tags) { var overlap = textSpan.Overlap(tagSpan.Span); if (overlap != null) { list.Add(new HexClassificationSpan(overlap.Value, tagSpan.Tag.ClassificationType)); } } if (list.Count <= 1) { if (list.Count == 1) { result.Add(list[0]); } return; } list.Sort(HexClassificationSpanComparer.Instance); // Common case if (!HasOverlaps(list)) { result.AddRange(Merge(list)); return; } int min = 0; int minOffset = textSpan.Start; var newList = new List <HexClassificationSpan>(); var ctList = new List <VSTC.IClassificationType>(); while (min < list.Count) { while (min < list.Count && minOffset >= list[min].Span.End) { min++; } if (min >= list.Count) { break; } var cspan = list[min]; minOffset = Math.Max(minOffset, cspan.Span.Start); int end = cspan.Span.End; ctList.Clear(); ctList.Add(cspan.ClassificationType); for (int i = min + 1; i < list.Count; i++) { cspan = list[i]; int cspanStart = cspan.Span.Start; if (cspanStart > minOffset) { if (cspanStart < end) { end = cspanStart; } break; } int cspanEnd = cspan.Span.End; if (minOffset >= cspanEnd) { continue; } if (cspanEnd < end) { end = cspanEnd; } if (!ctList.Contains(cspan.ClassificationType)) { ctList.Add(cspan.ClassificationType); } } Debug.Assert(minOffset < end); var ct = ctList.Count == 1 ? ctList[0] : classificationTypeRegistryService.CreateTransientClassificationType(ctList); newList.Add(new HexClassificationSpan(VST.Span.FromBounds(minOffset, end), ct)); minOffset = end; } Debug.Assert(!HasOverlaps(newList)); result.AddRange(Merge(newList)); return; }