/// <summary>
        /// Parses the specified line, searching for the start of a region.
        /// </summary>
        /// <param name="line">The line.</param>
        /// <param name="text">The text.</param>
        /// <param name="currentRegion">The current region.</param>
        /// <param name="regionStart">The region start.</param>
        /// <returns></returns>
        private static bool ParseRegionStart(ITextSnapshotLine line, string text, ref PartialRegion currentRegion, ref int regionStart)
        {
            var regionStartMatch = RegionRegex.RegionStart.Match(text);

            if (!regionStartMatch.Success)
            {
                return(false);
            }

            regionStart = regionStartMatch.Groups[1].Success
                ? regionStartMatch.Groups[1].Length
                : 0;

            var currentLevel = currentRegion != null
                ? currentRegion.Level
                : 1;

            currentRegion = new PartialRegion
            {
                Level         = currentLevel + 1,
                StartLine     = line.LineNumber,
                StartOffset   = regionStart,
                PartialParent = currentRegion
            };

            return(true);
        }
        /// <summary>
        /// Parses the current snapshot of <see cref="_buffer"/>.
        /// </summary>
        private void Parse()
        {
            var snapshot = _buffer.CurrentSnapshot;
            var regions  = new List <Region>();

            PartialRegion currentRegion = null;

            foreach (var line in snapshot.Lines)
            {
                var regionStart = -1;
                var text        = line.GetText();

                if (!ParseRegionStart(line, text, ref currentRegion, ref regionStart))
                {
                    ParseRegionEnd(regions, line, text, ref currentRegion, ref regionStart);
                }
            }

            var oldSpans = new List <Span>(_regions
                                           .Select(r => AsSnapshotSpan(r, _snapshot)
                                                   .TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive)
                                                   .Span));

            var newSpans = new List <Span>(regions
                                           .Select(r => AsSnapshotSpan(r, snapshot).Span));

            var oldSpanCollection = new NormalizedSpanCollection(oldSpans);
            var newSpanCollection = new NormalizedSpanCollection(newSpans);

            var removed = NormalizedSpanCollection.Difference(oldSpanCollection, newSpanCollection);

            var changeStart = int.MaxValue;
            var 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);
            }

            _snapshot = snapshot;
            _regions.Clear();
            _regions.AddRange(regions);

            if (changeStart <= changeEnd)
            {
                TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(new SnapshotSpan(_snapshot, Span.FromBounds(changeStart, changeEnd))));
            }
        }
        /// <summary>
        /// Parses the specified line, searching for the end of a region.
        /// </summary>
        /// <param name="regions">The regions.</param>
        /// <param name="line">The line.</param>
        /// <param name="text">The text.</param>
        /// <param name="currentRegion">The current region.</param>
        /// <param name="regionStart">The region start.</param>
        private static void ParseRegionEnd(List <Region> regions, ITextSnapshotLine line, string text, ref PartialRegion currentRegion, ref int regionStart)
        {
            var regionEndMatch = RegionRegex.RegionEnd.Match(text);

            if (!regionEndMatch.Success)
            {
                return;
            }

            regionStart = regionEndMatch.Groups[1].Success
                ? regionEndMatch.Groups[1].Length
                : 0;

            if (currentRegion == null)
            {
                return;
            }

            regions.Add(new Region
            {
                Level       = currentRegion.Level,
                StartLine   = currentRegion.StartLine,
                StartOffset = currentRegion.StartOffset,
                EndLine     = line.LineNumber
            });

            currentRegion = currentRegion.PartialParent;
        }