private void addStartRegion(
            string lineContent,
            int regionStart,
            int lineNumber,
            int regionStartHoverText,
            ref PartialRegion currentRegion,
            IList <Region> newRegions)
        {
            //AsmDudeToolsStatic.Output("INFO: CodeFoldingTagger: addStartRegion");
            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,
                    StartOffsetHoverText = regionStartHoverText,
                    EndLine              = lineNumber
                });

                currentRegion = new PartialRegion()
                {
                    Level                = newLevel,
                    StartLine            = lineNumber,
                    StartOffset          = regionStart,
                    StartOffsetHoverText = regionStartHoverText,
                    PartialParent        = currentRegion.PartialParent
                };
            }
            //this is a new (sub)region
            else
            {
                currentRegion = new PartialRegion()
                {
                    Level                = newLevel,
                    StartLine            = lineNumber,
                    StartOffset          = regionStart,
                    StartOffsetHoverText = regionStartHoverText,
                    PartialParent        = currentRegion
                };
            }
        }
 private void addEndRegion(
     string lineContent,
     int regionEnd,
     int lineNumber,
     ref PartialRegion currentRegion,
     IList <Region> newRegions)
 {
     //AsmDudeToolsStatic.Output("INFO: CodeFoldingTagger: addEndRegion: lineContent="+lineContent +"; regionEnd="+regionEnd +"; lineNumber="+lineNumber);
     if (currentRegion != null)
     {
         newRegions.Add(new Region()
         {
             Level                = currentRegion.Level,
             StartLine            = currentRegion.StartLine,
             StartOffset          = currentRegion.StartOffset,
             StartOffsetHoverText = currentRegion.StartOffsetHoverText,
             EndLine              = lineNumber
         });
         currentRegion = currentRegion.PartialParent;
     }
 }
        private void Parse()
        {
            if (!this._enabled)
            {
                return;
            }

            lock (this._updateLock)
            {
                DateTime time1 = DateTime.Now;

                ITextSnapshot  newSnapshot = this._buffer.CurrentSnapshot;
                IList <Region> newRegions  = new List <Region>();

                // keep the current (deepest) partial region, which will have
                // references to any parent partial regions.
                PartialRegion currentRegion = null;

                IEnumerator <ITextSnapshotLine> enumerator = newSnapshot.Lines.GetEnumerator();

                ITextSnapshotLine line = null;
                bool hasNext           = enumerator.MoveNext();
                bool already_advanced  = true;
                if (hasNext)
                {
                    line = enumerator.Current;
                }

                while (hasNext)
                {
                    already_advanced = false;

                    #region Parse Line
                    if (line.Length > 0)
                    {
                        string lineContent = line.GetText();
                        int    lineNumber  = line.LineNumber;

                        (int regionStart, int regionStartHoverText) = this.Is_Start_Keyword(lineContent, lineNumber);
                        if (regionStart != -1)
                        {
                            this.Add_Start_Region(lineContent, regionStart, lineNumber, regionStartHoverText, ref currentRegion, newRegions);
                        }
                        else
                        {
                            int regionEnd = this.Is_End_Keyword(lineContent, lineNumber);
                            if (regionEnd != -1)
                            {
                                this.Add_End_Region(lineContent, regionEnd, lineNumber, ref currentRegion, newRegions);
                            }
                            else
                            {
                                #region Search for multi-line Remark
                                if (AsmSourceTools.IsRemarkOnly(lineContent))
                                {
                                    int    lineNumber2  = -1;
                                    string lineContent2 = null;

                                    while (enumerator.MoveNext())
                                    {
                                        line = enumerator.Current;
                                        string lineContent3 = line.GetText();
                                        if (AsmSourceTools.IsRemarkOnly(lineContent3) &&
                                            (this.Is_Start_Directive_Keyword(lineContent3).StartPos == -1) &&
                                            (this.Is_End_Directive_Keyword(lineContent3) == -1))
                                        {
                                            lineNumber2      = line.LineNumber;
                                            lineContent2     = lineContent3;
                                            already_advanced = false;
                                        }
                                        else
                                        {
                                            already_advanced = true;
                                            break;
                                        }
                                    }
                                    if (lineNumber2 != -1)
                                    {
                                        int regionStartPos = AsmSourceTools.GetRemarkCharPosition(lineContent);
                                        this.Add_Start_Region(lineContent, regionStartPos, lineNumber, regionStartPos, ref currentRegion, newRegions);
                                        //this.updateChangedSpans(newSnapshot, newRegions);
                                        this.Add_End_Region(lineContent2, 0, lineNumber2, ref currentRegion, newRegions);
                                    }
                                }
                                #endregion
                            }
                        }
                    }
                    #endregion Parse Line

                    #region Update Changed Spans
                    this.Update_Changed_Spans(newSnapshot, newRegions);
                    #endregion

                    #region Advance to next line
                    if (!already_advanced)
                    {
                        hasNext = enumerator.MoveNext();
                        if (hasNext)
                        {
                            line = enumerator.Current;
                        }
                    }
                    #endregion
                }
                AsmDudeToolsStatic.Print_Speed_Warning(time1, "CodeFoldingTagger");

                double elapsedSec = (double)(DateTime.Now.Ticks - time1.Ticks) / 10000000;
                if (elapsedSec > AsmDudePackage.SlowShutdownThresholdSec)
                {
#                   if DEBUG
                    AsmDudeToolsStatic.Output_WARNING("CodeFoldingTagger: Parse: disabled CodeFolding had I been in Release mode");
#                   else
                    this.Disable();
#                   endif
                }
        private void ReParse()
        {
            //Debug.WriteLine("INFO:OutliningTagger:ReParse: entering");

            ITextSnapshot newSnapshot = _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)
            {
                int    regionStart = -1;
                string text        = line.GetText();

                //lines that contain a "[" denote the start of a new region.
                if ((regionStart = text.IndexOf(startHide, StringComparison.Ordinal)) != -1)
                {
                    int currentLevel = (currentRegion != null) ? currentRegion.Level : 1;
                    int newLevel;
                    if (!TryGetLevel(text, regionStart, out newLevel))
                    {
                        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   = regionStart,
                            PartialParent = currentRegion.PartialParent
                        };
                    }
                    //this is a new (sub)region
                    else
                    {
                        currentRegion = new PartialRegion()
                        {
                            Level         = newLevel,
                            StartLine     = line.LineNumber,
                            StartOffset   = regionStart,
                            PartialParent = currentRegion
                        };
                    }
                }
                //lines that contain "]" denote the end of a region
                else if ((regionStart = text.IndexOf(endHide, StringComparison.Ordinal)) != -1)
                {
                    int currentLevel = (currentRegion != null) ? currentRegion.Level : 1;
                    int closingLevel;
                    if (!TryGetLevel(text, regionStart, out closingLevel))
                    {
                        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;
                    }
                }
            }

            //determine the changed span, and send a changed event with the new spans
            List <Span> oldSpans =
                new List <Span>(this._regions.Select(r => AsSnapshotSpan(r, this._snapshot)
                                                     .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);
            }

            this._snapshot = newSnapshot;
            this._regions  = newRegions;

            if (changeStart <= changeEnd)
            {
                ITextSnapshot snap = this._snapshot;
                if (this.TagsChanged != null)
                {
                    this.TagsChanged(this, new SnapshotSpanEventArgs(
                                         new SnapshotSpan(this._snapshot, Span.FromBounds(changeStart, changeEnd))));
                }
            }
            //Debug.WriteLine("INFO:OutliningTagger:ReParse: leaving");
        }
        private void parse(object threadContext)
        {
            if (!this._enabled)
            {
                return;
            }

            this._waiting = true;
            Thread.Sleep(AsmDudePackage.msSleepBeforeAsyncExecution);
            this._busy    = true;
            this._waiting = false;

            #region Payload
            lock (_updateLock) {
                DateTime time1 = DateTime.Now;

                ITextSnapshot  newSnapshot = _buffer.CurrentSnapshot;
                IList <Region> newRegions  = new List <Region>();

                // keep the current (deepest) partial region, which will have
                // references to any parent partial regions.
                PartialRegion currentRegion = null;

                IEnumerator <ITextSnapshotLine> enumerator = newSnapshot.Lines.GetEnumerator();

                ITextSnapshotLine line = null;
                bool hasNext           = enumerator.MoveNext();
                bool already_advanced  = true;
                if (hasNext)
                {
                    line = enumerator.Current;
                }

                while (hasNext)
                {
                    already_advanced = false;

                    #region Parse Line
                    if (line.Length > 0)
                    {
                        string lineContent = line.GetText();
                        int    lineNumber  = line.LineNumber;

                        Tuple <int, int> tup     = this.isStartKeyword(lineContent, lineNumber);
                        int regionStart          = tup.Item1;
                        int regionStartHoverText = tup.Item2;

                        if (regionStart != -1)
                        {
                            this.addStartRegion(lineContent, regionStart, lineNumber, regionStartHoverText, ref currentRegion, newRegions);
                        }
                        else
                        {
                            int regionEnd = this.isEndKeyword(lineContent, lineNumber);
                            if (regionEnd != -1)
                            {
                                this.addEndRegion(lineContent, regionEnd, lineNumber, ref currentRegion, newRegions);
                            }
                            else
                            {
                                #region Search for multi-line Remark
                                if (AsmSourceTools.isRemarkOnly(lineContent))
                                {
                                    int    lineNumber2  = -1;
                                    string lineContent2 = null;

                                    while (enumerator.MoveNext())
                                    {
                                        line = enumerator.Current;
                                        string lineContent3 = line.GetText();
                                        if (AsmSourceTools.isRemarkOnly(lineContent3) &&
                                            (this.isStartDirectiveKeyword(lineContent3).Item1 == -1) &&
                                            (this.isEndDirectiveKeyword(lineContent3) == -1))
                                        {
                                            lineNumber2      = line.LineNumber;
                                            lineContent2     = lineContent3;
                                            already_advanced = false;
                                        }
                                        else
                                        {
                                            already_advanced = true;
                                            break;
                                        }
                                    }
                                    if (lineNumber2 != -1)
                                    {
                                        int regionStartPos = AsmSourceTools.getRemarkCharPosition(lineContent);
                                        this.addStartRegion(lineContent, regionStartPos, lineNumber, regionStartPos, ref currentRegion, newRegions);
                                        //this.updateChangedSpans(newSnapshot, newRegions);
                                        this.addEndRegion(lineContent2, 0, lineNumber2, ref currentRegion, newRegions);
                                    }
                                }
                                #endregion
                            }
                        }
                    }
                    #endregion Parse Line

                    #region Update Changed Spans
                    this.updateChangedSpans(newSnapshot, newRegions);
                    #endregion

                    #region Advance to next line
                    if (!already_advanced)
                    {
                        hasNext = enumerator.MoveNext();
                        if (hasNext)
                        {
                            line = enumerator.Current;
                        }
                    }
                    #endregion
                }
                AsmDudeToolsStatic.printSpeedWarning(time1, "CodeFoldingTagger");

                double elapsedSec = (double)(DateTime.Now.Ticks - time1.Ticks) / 10000000;
                if (elapsedSec > AsmDudePackage.slowShutdownThresholdSec)
                {
                    this.disable();
                }
            }
            #endregion Payload

            this._busy = false;
            if (this._scheduled)
            {
                this._scheduled = false;
                this.parse_Delayed();
            }
        }