private void AddBlocksToEnd(SnapshotSpan span, bool cache)
        {
            TrackedBlock prevBlock    = null;
            int          prevBlockEnd = 0;

            if (this.trackedBlocks.Count > 0)
            {
                prevBlock    = this.trackedBlocks[this.trackedBlocks.Count - 1];
                prevBlockEnd = prevBlock.Block.GetEndPoint(span.Snapshot);
                if (prevBlockEnd >= span.End.Position)
                {
                    return;
                }
            }
            int nextBlockEnd = Math.Min(prevBlockEnd + BlockSize, span.Snapshot.Length);

            if (nextBlockEnd > prevBlockEnd)
            {
                TrackedBlock nextBlock = new TrackedBlock();
                nextBlock.Block      = span.Snapshot.CreateTrackingSpan(Span.FromBounds(prevBlockEnd, nextBlockEnd), SpanTrackingMode.EdgeExclusive);
                nextBlock.StartState = prevBlock?.EndState;
                this.trackedBlocks.Add(nextBlock);
                int index = this.trackedBlocks.Count - 1;
                this.UpdateBlock(span, ref index, cache);
            }
        }
 private void CacheBlock(SnapshotSpan span, TrackedBlock block)
 {
     if (block.CachedClassifications.Count == 0)
     {
         this.LexBlock(span, block, true);
     }
 }
        private void UpdateBlocks(SnapshotSpan span, bool cache)
        {
            int index = this.FindBlockIndex(span, span.Start.Position, false);

            while (index < this.trackedBlocks.Count)
            {
                TrackedBlock block     = this.trackedBlocks[index];
                Span         blockSpan = block.Block.GetSpan(span.Snapshot);
                if (blockSpan.Length == 0)
                {
                    this.trackedBlocks.RemoveAt(index);
                }
                else
                {
                    if (blockSpan.Start >= span.End.Position)
                    {
                        return;
                    }
                    if (block.Version != span.Snapshot.Version || (cache && block.CachedClassifications.Count == 0 && blockSpan.Length > 0))
                    {
                        this.UpdateBlock(span, ref index, cache);
                    }
                    ++index;
                }
            }
            this.AddBlocksToEnd(span, cache);
        }
        public IList <ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
        {
            List <ClassificationSpan> result = new List <ClassificationSpan>();

            this.UpdateBlocks(span, true);
            int position = span.Start.Position;
            int index    = this.FindBlockIndex(span, span.Start.Position, false);

            while (index < this.trackedBlocks.Count)
            {
                TrackedBlock block = this.trackedBlocks[index];
                this.CacheBlock(span, block);
                int classificationStartPosition = block.Block.GetStartPoint(span.Snapshot);
                int classificationIndex         = 0;
                while (classificationIndex < block.CachedClassifications.Count && position < span.End.Position)
                {
                    ClassificationSpan classification = block.CachedClassifications[classificationIndex];
                    int classificationEndPosition     = classificationStartPosition + classification.Span.Length;
                    if (span.OverlapsWith(Span.FromBounds(classificationStartPosition, classificationEndPosition)))
                    {
                        result.Add(classification);
                    }
                    ++classificationIndex;
                    classificationStartPosition = classificationEndPosition;
                    if (classificationEndPosition >= span.End.Position)
                    {
                        return(result);
                    }
                }
                ++index;
            }
            return(result);
        }
        private void InvalidateBlock(SnapshotSpan span, TrackedBlock block)
        {
            Span blockSpan = block.Block.GetSpan(span.Snapshot);

            if (span.Contains(blockSpan))
            {
                return;
            }
            if (span.Start.Position > blockSpan.Start && span.Start.Position < blockSpan.End)
            {
                this.Invalidate(this.CreateSnapshotSpan(span, blockSpan.Start, span.Start.Position));
            }
            if (span.End.Position > blockSpan.Start && span.End.Position < blockSpan.End)
            {
                this.Invalidate(this.CreateSnapshotSpan(span, span.End.Position, blockSpan.End));
            }
            if (span.Start.Position >= blockSpan.End || span.End.Position <= blockSpan.Start)
            {
                this.Invalidate(this.CreateSnapshotSpan(span, blockSpan.Start, blockSpan.End));
            }
        }
        private void InvalidateBlockEdge(SnapshotSpan span, TrackedBlock block)
        {
            Span blockSpan = block.Block.GetSpan(span.Snapshot);

            if (span.Contains(blockSpan))
            {
                return;
            }
            int startIndex = -1;
            int endIndex   = -1;

            for (int i = 0; i < block.CachedClassifications.Count; i++)
            {
                Span classificationSpan = block.CachedClassifications[i].Span.Span;
                if (classificationSpan.Contains(span.Start.Position))
                {
                    startIndex = i;
                }
                if (classificationSpan.Contains(span.End.Position))
                {
                    endIndex = i;
                    break;
                }
            }
            if (startIndex >= 0)
            {
                Span classificationSpan = block.CachedClassifications[startIndex].Span.Span;
                if (classificationSpan.Start < span.Start.Position)
                {
                    this.Invalidate(this.CreateSnapshotSpan(span, classificationSpan.Start, span.Start.Position));
                }
            }
            if (span.End.Position > blockSpan.Start && span.End.Position < blockSpan.End)
            {
                this.Invalidate(this.CreateSnapshotSpan(span, span.End.Position, blockSpan.End));
            }
        }
        private void LexBlock(SnapshotSpan span, TrackedBlock block, bool cache)
        {
            this.InvalidateBlockEdge(span, block);
            block.ClearCache();
            block.Version = span.Snapshot.Version;

            Span   textSpan = block.Block.GetSpan(span.Snapshot);
            string text     = span.Snapshot.GetText(textSpan);

            this.lexer.Reset();
            this.lexer.SetInputStream(new AntlrInputStream(text));
            if (block.StartState == null)
            {
                block.StartState = this.SaveLexerState();
            }
            else
            {
                block.StartState.Restore(this.lexer);
            }

            IToken token         = null;
            int    tokenType     = -1;
            int    startPosition = textSpan.Start;
            int    endPosition   = startPosition;
            int    blockEnd      = startPosition + BlockSize;

            do
            {
                LexerState state = this.SaveLexerState();
                token = lexer.NextToken();

                if (lexer._hitEOF)
                {
                    tokenType   = -1;
                    endPosition = textSpan.End;
                }
                else if (token != null)
                {
                    tokenType    = token.Type;
                    endPosition += token.StopIndex - token.StartIndex + 1;
                }
                if (token == null || tokenType < 0)
                {
                    int textLength = endPosition - startPosition;
                    int delta      = 0;
                    tokenType = -1;
                    while (tokenType < 0 && startPosition + textLength < span.Snapshot.Length)
                    {
                        delta      += 1024;
                        textLength += Math.Min(span.Snapshot.Length - startPosition - textLength, delta);
                        string currentText = span.Snapshot.GetText(startPosition, textLength);
                        textLength = currentText.Length;

                        this.lexer.Reset();
                        this.lexer.SetInputStream(new AntlrInputStream(currentText));
                        state.Restore(this.lexer);

                        token = lexer.NextToken();

                        if (lexer._hitEOF)
                        {
                            endPosition = startPosition + textLength;
                        }
                        else if (token != null)
                        {
                            tokenType   = token.Type;
                            endPosition = startPosition + token.StopIndex - token.StartIndex + 1;
                        }
                        else
                        {
                            endPosition = startPosition + textLength;
                        }
                    }
                }

                if (cache)
                {
                    var classification     = this.GetClassificationType(tokenType, this.lexer._mode);
                    var tokenSpan          = this.CreateSnapshotSpan(span, startPosition, endPosition);
                    var classificationSpan = new ClassificationSpan(tokenSpan, classification);
                    block.CacheClassification(classificationSpan);
                }

                startPosition = endPosition;
            }while (token != null && startPosition < textSpan.End && startPosition < blockEnd);

            Span blockSpan = Span.FromBounds(textSpan.Start, endPosition);

            block.Block    = span.Snapshot.CreateTrackingSpan(blockSpan, textSpan.Start == 0 ? SpanTrackingMode.EdgeInclusive : SpanTrackingMode.EdgePositive);
            block.EndState = this.SaveLexerState();
            this.InvalidateBlockEdge(span, block);
        }
        private void UpdateBlock(SnapshotSpan span, ref int index, bool cache)
        {
            bool         invalidate = false;
            TrackedBlock block      = this.trackedBlocks[index];

            while (block != null)
            {
                Span blockSpan = block.Block.GetSpan(span.Snapshot);
                this.LexBlock(span, block, cache && (blockSpan.Start < span.End.Position));
                blockSpan = block.Block.GetSpan(span.Snapshot);
                if (invalidate)
                {
                    this.InvalidateBlock(span, block);
                }

                TrackedBlock nextBlock = null;
                ++index;
                if (index < this.trackedBlocks.Count)
                {
                    while (index < this.trackedBlocks.Count)
                    {
                        nextBlock = this.trackedBlocks[index];
                        Span nextBlockSpan = nextBlock.Block.GetSpan(span.Snapshot);
                        if (nextBlockSpan.End <= blockSpan.End)
                        {
                            this.trackedBlocks.RemoveAt(index);
                        }
                        else if (nextBlockSpan.Start > blockSpan.End)
                        {
                            int nextBlockEnd = Math.Min(blockSpan.End + BlockSize, nextBlockSpan.Start);
                            nextBlock            = new TrackedBlock();
                            nextBlock.Block      = span.Snapshot.CreateTrackingSpan(Span.FromBounds(blockSpan.End, nextBlockEnd), SpanTrackingMode.EdgeExclusive);
                            nextBlock.StartState = block.EndState;
                            this.trackedBlocks.Insert(index, nextBlock);
                            break;
                        }
                        else
                        {
                            if (nextBlockSpan.Start == blockSpan.End && nextBlock.StartState.Equals(block.EndState))
                            {
                                return;
                            }
                            else
                            {
                                nextBlock.Block      = span.Snapshot.CreateTrackingSpan(Span.FromBounds(blockSpan.End, nextBlockSpan.End), SpanTrackingMode.EdgeExclusive);
                                nextBlock.StartState = block.EndState;
                                break;
                            }
                        }
                    }
                }
                else if (blockSpan.End < span.End.Position)
                {
                    int nextBlockEnd = Math.Min(blockSpan.End + BlockSize, span.Snapshot.Length);
                    nextBlock            = new TrackedBlock();
                    nextBlock.Block      = span.Snapshot.CreateTrackingSpan(Span.FromBounds(blockSpan.End, nextBlockEnd), SpanTrackingMode.EdgeExclusive);
                    nextBlock.StartState = block.EndState;
                    this.trackedBlocks.Add(nextBlock);
                }
                block      = nextBlock;
                invalidate = true;
            }
        }