private void CheckIfTagsChanged(SnapshotRegions oldSnapshotRegions, SnapshotRegions newSnapshotRegions) { ITextSnapshot oldSnapshot = oldSnapshotRegions.Snapshot; IReadOnlyList <Region> oldRegions = oldSnapshotRegions.Regions; ITextSnapshot newSnapshot = newSnapshotRegions.Snapshot; IReadOnlyList <Region> newRegions = newSnapshotRegions.Regions; // Determine the changed spans and send a changed event with the new spans. List <Span> oldSpans = new List <Span>( oldRegions.Select(r => AsSnapshotSpan(r, oldSnapshot).TranslateTo(newSnapshot, SpanTrackingMode.EdgeExclusive).Span)); List <Span> newSpans = new List <Span>(newRegions.Select(r => AsSnapshotSpan(r, newSnapshot).Span)); NormalizedSpanCollection oldSpanCollection = new NormalizedSpanCollection(oldSpans); NormalizedSpanCollection newSpanCollection = new NormalizedSpanCollection(newSpans); // The changed regions are regions that appear in one set or the other, but not both. NormalizedSpanCollection removed = NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection); int changeStart = int.MaxValue; int changeEnd = -1; if (removed.Count > 0) { changeStart = removed[0].Start; changeEnd = removed[removed.Count - 1].End; } if (newSpans.Count > 0) { changeStart = Math.Min(changeStart, newSpans[0].Start); changeEnd = Math.Max(changeEnd, newSpans[newSpans.Count - 1].End); } if (changeStart <= changeEnd) { var handler = this.TagsChanged; if (handler != null) { var args = new SnapshotSpanEventArgs(new SnapshotSpan(newSnapshot, Span.FromBounds(changeStart, changeEnd))); handler(this, args); } } }
public OutliningTagger(ITextBuffer buffer, ScanInfo scanInfo) { this.buffer = buffer; if (scanInfo != null) { // Our RegionHandler's GetRegionBeginRegex only looks for single line comment tokens // when doing Collapse/ExpandAllRegions, so we'll use the same restriction here. this.startExpressions = scanInfo.GetTokenRegexes(StartToken, true).ToList(); this.endExpressions = scanInfo.GetTokenRegexes(EndToken, true).Concat(scanInfo.GetTokenRegexes(AltEndToken, true)).ToList(); } else { // If we don't have scan info, then we can't provide tags. this.startExpressions = CollectionUtility.EmptyArray <Regex>(); this.endExpressions = CollectionUtility.EmptyArray <Regex>(); } this.snapshotRegions = new SnapshotRegions(buffer.CurrentSnapshot, CollectionUtility.EmptyArray <Region>()); this.buffer.Changed += this.BufferChanged; this.BackgroundReparse(); }
private void Reparse() { ITextSnapshot newSnapshot = this.buffer.CurrentSnapshot; List <Region> newRegions = new List <Region>(); // Keep the current (deepest) partial region, which will have references to any parent partial regions. PartialRegion currentRegion = null; foreach (var line in newSnapshot.Lines) { string text = line.GetText(); // Lines that match a start regex denote the start of a new region. Match startMatch = this.startExpressions.Select(regex => regex.Match(text)).FirstOrDefault(m => m.Success); if (startMatch != null) { int matchStartIndex = startMatch.Index; int currentLevel = (currentRegion != null) ? currentRegion.Level : 1; int newLevel = currentLevel + 1; // Levels are the same, and we have an existing region; // End the current region and start the next. if (currentLevel == newLevel && currentRegion != null) { newRegions.Add(new Region() { Level = currentRegion.Level, StartLine = currentRegion.StartLine, StartOffset = currentRegion.StartOffset, EndLine = line.LineNumber }); currentRegion = new PartialRegion() { Level = newLevel, StartLine = line.LineNumber, StartOffset = matchStartIndex, PartialParent = currentRegion.PartialParent }; } else { // This is a new (sub)region currentRegion = new PartialRegion() { Level = newLevel, StartLine = line.LineNumber, StartOffset = matchStartIndex, PartialParent = currentRegion }; } } else { // Lines that match an end regex denote the end of a region Match endMatch = this.endExpressions.Select(regex => regex.Match(text)).FirstOrDefault(m => m.Success); if (endMatch != null) { int currentLevel = (currentRegion != null) ? currentRegion.Level : 1; int closingLevel = currentLevel; // The regions match if (currentRegion != null && currentLevel == closingLevel) { newRegions.Add(new Region() { Level = currentLevel, StartLine = currentRegion.StartLine, StartOffset = currentRegion.StartOffset, EndLine = line.LineNumber }); currentRegion = currentRegion.PartialParent; } } } } SnapshotRegions newSnapshotRegions = new SnapshotRegions(newSnapshot, newRegions); SnapshotRegions oldSnapshotRegions; lock (this.resourceLock) { oldSnapshotRegions = this.snapshotRegions; this.snapshotRegions = newSnapshotRegions; } this.CheckIfTagsChanged(oldSnapshotRegions, newSnapshotRegions); }