/// <summary> /// parses buffer /// </summary> /// <param name="parser"></param> /// <param name="parent">parent region or null</param> /// <returns>a region with its children or null</returns> public static TextRegion ParseBuffer(SnapshotParser parser, TextRegion parent) { for (; !parser.AtEnd(); parser.MoveNext()) { TextRegion r = TextRegion.TryCreateRegion(parser); if (r != null) { parser.MoveNext(); //found the start of the region if (!r.Complete) { //searching for child regions while (TextRegion.ParseBuffer(parser, r) != null) { ; } //found everything r.ExtendStartPoint(); } //adding to children or merging with last child r.Parent = parent; parent.Children.Add(r); return(r); } //found parent's end - terminating parsing if (parent.TryComplete(parser)) { parser.MoveNext(); return(null); } } return(null); }
//Add a method that parses the buffer. The example given here is for illustration only. //It synchronously parses the buffer into nested outlining regions. private void Outline() { ITextSnapshot snapshot = Buffer.CurrentSnapshot; TextRegion regionTree = new TextRegion(); SnapshotParser parser = new SnapshotParser(snapshot, Classifier); //parsing snapshot while (TextRegion.ParseBuffer(parser, regionTree) != null) { ; } List <TextRegion> newRegions = GetRegionList(regionTree); List <Span> oldSpans = Regions.ConvertAll(r => r.AsSnapshotSpan().TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive).Span); List <Span> newSpans = newRegions.ConvertAll(r => r.AsSnapshotSpan().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); } this.Snapshot = snapshot; this.Regions = newRegions; if (changeStart <= changeEnd && this.TagsChanged != null) { this.TagsChanged(this, new SnapshotSpanEventArgs( new SnapshotSpan(this.Snapshot, Span.FromBounds(changeStart, changeEnd)))); } }
/// <summary> /// Tries to move region start point up to get C#-like outlining /// /// for (var k in obj) /// { -- from here /// /// for (var k in obj) -- to here /// { /// </summary> private void ExtendStartPoint() { //some are not extended if (!Complete || StartLine.LineNumber == EndLine.LineNumber || !string.IsNullOrWhiteSpace(TextBefore)) { return; } //how much can we move region start int upperLimit = 0; if (this.Parent != null) { int childPosition = Parent.Children.IndexOf(this); if (childPosition == 0) { //this region is first child of its parent //we can go until the parent's start upperLimit = Parent.RegionType != TextRegionType.None ? Parent.StartLine.LineNumber + 1 : 0; } else { //there is previous child //we can go until its end TextRegion prevRegion = Parent.Children[childPosition - 1]; upperLimit = prevRegion.EndLine.LineNumber + (prevRegion.EndLine.LineNumber == prevRegion.StartLine.LineNumber ? 0 : 1); } } //now looking up to calculated upper limit for non-empty line for (int i = StartLine.LineNumber - 1; i >= upperLimit; i--) { ITextSnapshotLine line = StartPoint.Snapshot.GetLineFromLineNumber(i); if (!string.IsNullOrWhiteSpace(line.GetText())) { //found such line, placing region start at its end StartPoint = line.End; return; } } }
private List <TextRegion> GetRegionList(TextRegion tree) { List <TextRegion> res = new List <TextRegion>(tree.Children.Count); foreach (TextRegion r in tree.Children) { if (r.Complete && r.StartLine.LineNumber != r.EndLine.LineNumber) { res.Add(r); } if (r.Children.Count != 0) { res.AddRange(GetRegionList(r)); } } //assigning tagger foreach (TextRegion r in res) { r.Tagger = this; } return(res); }