void PushStack(SyntaxMatch curMatch, IEnumerable <SyntaxContext> nextContexts)
            {
                if (nextContexts != null)
                {
                    bool first = true;
                    foreach (var nextContext in nextContexts)
                    {
                        var ctx = nextContext;
                        if (curMatch.WithPrototype != null)
                        {
                            ctx = new SyntaxContextWithPrototype(nextContext, curMatch.WithPrototype);
                        }

                        if (first)
                        {
                            MatchStack = MatchStack.Push(curMatch);
                            first      = false;
                        }
                        else
                        {
                            MatchStack = MatchStack.Push(null);
                        }
                        ContextStack = ContextStack.Push(ctx);
                        PushScopeStack(ctx.MetaScope);
                        PushScopeStack(ctx.MetaContentScope);
                    }
                }
            }
 void PopMetaContentScopeStack(SyntaxContext currentContext, SyntaxMatch curMatch)
 {
     if (ContextStack.Count() == 1)
     {
         return;
     }
     PopScopeStack(currentContext.MetaContentScope);
 }
            void PopStack(SyntaxContext currentContext, SyntaxMatch curMatch)
            {
                if (ContextStack.Count() == 1)
                {
                    MatchStack = MatchStack.Clear();
                    ScopeStack = new ScopeStack(highlighting.definition.Scope);
                    return;
                }
                ContextStack = ContextStack.Pop();
                if (!MatchStack.IsEmpty)
                {
                    PopScopeStack(MatchStack.Peek()?.Scope);
                    MatchStack = MatchStack.Pop();
                }
                PopScopeStack(currentContext.MetaScope);

                if (curMatch.Scope.Count > 0 && !ScopeStack.IsEmpty)
                {
                    for (int i = 0; i < curMatch.Scope.Count; i++)
                    {
                        ScopeStack = ScopeStack.Pop();
                    }
                }
            }
            public Task <HighlightedLine> GetColoredSegments(ITextSource text, int startOffset, int length, CancellationToken cancellationToken = default)
            {
                if (ContextStack.IsEmpty || length > maxLineLength)
                {
                    return(Task.FromResult(new HighlightedLine(new TextSegment(startOffset, length), new [] { new ColoredSegment(0, length, ScopeStack.Empty) })));
                }
                SyntaxContext currentContext     = null;
                Match         match              = null;
                SyntaxMatch   curMatch           = null;
                var           segments           = new List <ColoredSegment> ();
                int           offset             = 0;
                int           curSegmentOffset   = 0;
                int           endOffset          = offset + length;
                int           lastMatch          = -1;
                var           highlightedSegment = new TextSegment(startOffset, length);
                string        lineText           = text.GetTextAt(startOffset, length);
                var           initialState       = state.Clone();
                int           timeoutOccursAt;

                unchecked {
                    timeoutOccursAt = Environment.TickCount + (int)matchTimeout.TotalMilliseconds;
                }
restart:
                if (cancellationToken.IsCancellationRequested)
                {
                    return(Task.FromResult(new HighlightedLine(new TextSegment(startOffset, length), new [] { new ColoredSegment(0, length, ScopeStack.Empty) })));
                }
                if (offset >= lineText.Length)
                {
                    goto end;
                }
                lastMatch      = offset;
                currentContext = ContextStack.Peek();
                match          = null;
                curMatch       = null;
                foreach (var m in currentContext.Matches)
                {
                    if (m.GotTimeout)
                    {
                        continue;
                    }
                    var r = m.GetRegex();
                    if (r == null)
                    {
                        continue;
                    }
                    try {
                        Match possibleMatch;
                        if (r.pattern == "(?<=\\})" && offset > 0)                           // HACK to fix typescript highlighting.
                        {
                            possibleMatch = r.Match(lineText, offset - 1, length, matchTimeout);
                        }
                        else
                        {
                            possibleMatch = r.Match(lineText, offset, length, matchTimeout);
                        }
                        if (possibleMatch.Success)
                        {
                            if (match == null || possibleMatch.Index < match.Index)
                            {
                                match    = possibleMatch;
                                curMatch = m;
                                // Console.WriteLine (match.Index + " possible match : " + m + "/" + possibleMatch.Index + "-" + possibleMatch.Length);
                            }
                            else
                            {
                                // Console.WriteLine (match.Index + " skip match : " + m + "/" + possibleMatch.Index + "-" + possibleMatch.Length);
                            }
                        }
                        else
                        {
                            // Console.WriteLine ("fail match : " + m);
                        }
                    } catch (RegexMatchTimeoutException) {
                        LoggingService.LogWarning("Warning: Regex " + m.Match + " timed out on line:" + text.GetTextAt(offset, length));
                        m.GotTimeout = true;
                        continue;
                    }
                }
                if (length <= 0 && curMatch == null)
                {
                    goto end;
                }

                if (Environment.TickCount >= timeoutOccursAt)
                {
                    if (curMatch != null)
                    {
                        curMatch.GotTimeout = true;
                    }
                    goto end;
                }

                if (match != null)
                {
                    // Console.WriteLine (match.Index + " taken match : " + curMatch + "/" + match.Index + "-" + match.Length);
                    var matchEndOffset = match.Index + match.Length;
                    if (curSegmentOffset < match.Index && match.Length > 0)
                    {
                        segments.Add(new ColoredSegment(curSegmentOffset, match.Index - curSegmentOffset, ScopeStack));
                        curSegmentOffset = match.Index;
                    }
                    if (curMatch.Pop)
                    {
                        PopMetaContentScopeStack(currentContext, curMatch);
                    }

                    PushScopeStack(curMatch.Scope);

                    if (curMatch.Captures.Groups.Count > 0)
                    {
                        for (int i = 0; i < curMatch.Captures.Groups.Count; ++i)
                        {
                            var capture = curMatch.Captures.Groups[i];
                            var grp     = match.Groups [capture.Item1];
                            if (grp == null || grp.Length == 0)
                            {
                                continue;
                            }
                            if (curSegmentOffset < grp.Index)
                            {
                                ReplaceSegment(segments, new ColoredSegment(curSegmentOffset, grp.Index - curSegmentOffset, ScopeStack));
                            }
                            ReplaceSegment(segments, new ColoredSegment(grp.Index, grp.Length, ScopeStack.Push(capture.Item2)));
                            curSegmentOffset = Math.Max(curSegmentOffset, grp.Index + grp.Length);
                        }
                    }

                    if (curMatch.Captures.NamedGroups.Count > 0)
                    {
                        for (int i = 0; i < curMatch.Captures.NamedGroups.Count; ++i)
                        {
                            var capture = curMatch.Captures.NamedGroups[i];
                            var grp     = match.Groups [capture.Item1];
                            if (grp == null || grp.Length == 0)
                            {
                                continue;
                            }
                            if (curSegmentOffset < grp.Index)
                            {
                                ReplaceSegment(segments, new ColoredSegment(curSegmentOffset, grp.Index - curSegmentOffset, ScopeStack));
                            }
                            ReplaceSegment(segments, new ColoredSegment(grp.Index, grp.Length, ScopeStack.Push(capture.Item2)));
                            curSegmentOffset = grp.Index + grp.Length;
                        }
                    }

                    if (curMatch.Scope.Count > 0 && curSegmentOffset < matchEndOffset && match.Length > 0)
                    {
                        segments.Add(new ColoredSegment(curSegmentOffset, matchEndOffset - curSegmentOffset, ScopeStack));
                        curSegmentOffset = matchEndOffset;
                    }

                    if (curMatch.Pop)
                    {
                        if (matchEndOffset - curSegmentOffset > 0)
                        {
                            segments.Add(new ColoredSegment(curSegmentOffset, matchEndOffset - curSegmentOffset, ScopeStack));
                        }
                        //if (curMatch.Scope != null)
                        //	scopeStack = scopeStack.Pop ();
                        PopStack(currentContext, curMatch);
                        curSegmentOffset = matchEndOffset;
                    }
                    else if (curMatch.Set != null)
                    {
                        // if (matchEndOffset - curSegmentOffset > 0)
                        //	segments.Add (new ColoredSegment (curSegmentOffset, matchEndOffset - curSegmentOffset, ScopeStack));
                        //if (curMatch.Scope != null)
                        //	scopeStack = scopeStack.Pop ();
                        PopMetaContentScopeStack(currentContext, curMatch);
                        PopStack(currentContext, curMatch);
                        //curSegmentOffset = matchEndOffset;
                        var nextContexts = curMatch.Set.GetContexts(currentContext);
                        PushStack(curMatch, nextContexts);
                        goto skip;
                    }
                    else if (curMatch.Push != null)
                    {
                        var nextContexts = curMatch.Push.GetContexts(currentContext);
                        PushStack(curMatch, nextContexts);
                    }
                    else
                    {
                        if (curMatch.Scope.Count > 0)
                        {
                            for (int i = 0; i < curMatch.Scope.Count; i++)
                            {
                                ScopeStack = ScopeStack.Pop();
                            }
                        }
                    }

                    if (curSegmentOffset < matchEndOffset && match.Length > 0)
                    {
                        segments.Add(new ColoredSegment(curSegmentOffset, matchEndOffset - curSegmentOffset, ScopeStack));
                        curSegmentOffset = matchEndOffset;
                    }
skip:
                    length -= curSegmentOffset - offset;
                    offset  = curSegmentOffset;
                    goto restart;
                }

end:
                if (endOffset - curSegmentOffset > 0)
                {
                    segments.Add(new ColoredSegment(curSegmentOffset, endOffset - curSegmentOffset, ScopeStack));
                }

                return(Task.FromResult(new HighlightedLine(highlightedSegment, segments)
                {
                    IsContinuedBeyondLineEnd = !initialState.Equals(state)
                }));
            }
 internal void AddMatch(SyntaxMatch match)
 {
     this.matches.Add(match);
 }
            public Task <HighlightedLine> GetColoredSegments(ITextSource text, int startOffset, int length)
            {
                if (ContextStack.IsEmpty)
                {
                    return(Task.FromResult(new HighlightedLine(new TextSegment(startOffset, length), new [] { new ColoredSegment(0, length, ScopeStack.Empty) })));
                }
                SyntaxContext        currentContext = null;
                List <SyntaxContext> lastContexts   = new List <SyntaxContext> ();
                Match       match              = null;
                SyntaxMatch curMatch           = null;
                var         segments           = new List <ColoredSegment> ();
                int         offset             = 0;
                int         curSegmentOffset   = 0;
                int         endOffset          = offset + length;
                int         lastMatch          = -1;
                var         highlightedSegment = new TextSegment(startOffset, length);
                string      lineText           = text.GetTextAt(startOffset, length);

restart:
                if (lastMatch == offset)
                {
                    if (lastContexts.Contains(currentContext))
                    {
                        offset++;
                        length--;
                    }
                    else
                    {
                        lastContexts.Add(currentContext);
                    }
                }
                else
                {
                    lastContexts.Clear();
                    lastContexts.Add(currentContext);
                }
                if (length <= 0)
                {
                    goto end;
                }
                lastMatch      = offset;
                currentContext = ContextStack.Peek();
                match          = null;
                curMatch       = null;
                foreach (var m in currentContext.Matches)
                {
                    if (m.GotTimeout)
                    {
                        continue;
                    }
                    var r = m.GetRegex();
                    if (r == null)
                    {
                        continue;
                    }
                    try {
                        var possibleMatch = r.Match(lineText, offset, length, matchTimeout);
                        if (possibleMatch.Success)
                        {
                            if (match == null || possibleMatch.Index < match.Index)
                            {
                                match    = possibleMatch;
                                curMatch = m;
                                // Console.WriteLine (match.Index + " possible match : " + m + "/" + possibleMatch.Index + "-" + possibleMatch.Length);
                            }
                            else
                            {
                                // Console.WriteLine (match.Index + " skip match : " + m + "/" + possibleMatch.Index + "-" + possibleMatch.Length);
                            }
                        }
                        else
                        {
                            // Console.WriteLine ("fail match : " + m);
                        }
                    } catch (RegexMatchTimeoutException) {
                        LoggingService.LogWarning("Warning: Regex " + m.Match + " timed out on line:" + text.GetTextAt(offset, length));
                        m.GotTimeout = true;
                        continue;
                    }
                }

                if (match != null)
                {
                    // Console.WriteLine (match.Index + " taken match : " + curMatch + "/" + match.Index + "-" + match.Length);
                    var matchEndOffset = match.Index + match.Length;
                    if (curSegmentOffset < match.Index && match.Length > 0)
                    {
                        segments.Add(new ColoredSegment(curSegmentOffset, match.Index - curSegmentOffset, ScopeStack));
                        curSegmentOffset = match.Index;
                    }
                    if (curMatch.Pop)
                    {
                        PopMetaContentScopeStack(currentContext, curMatch);
                    }

                    PushScopeStack(curMatch.Scope);

                    if (curMatch.Captures.Groups.Count > 0)
                    {
                        for (int i = 0; i < curMatch.Captures.Groups.Count; ++i)
                        {
                            var capture = curMatch.Captures.Groups[i];
                            var grp     = match.Groups [capture.Item1];
                            if (grp == null || grp.Length == 0)
                            {
                                continue;
                            }
                            if (curSegmentOffset < grp.Index)
                            {
                                ReplaceSegment(segments, new ColoredSegment(curSegmentOffset, grp.Index - curSegmentOffset, ScopeStack));
                            }
                            ReplaceSegment(segments, new ColoredSegment(grp.Index, grp.Length, ScopeStack.Push(capture.Item2)));
                            curSegmentOffset = Math.Max(curSegmentOffset, grp.Index + grp.Length);
                        }
                    }

                    if (curMatch.Captures.NamedGroups.Count > 0)
                    {
                        for (int i = 0; i < curMatch.Captures.NamedGroups.Count; ++i)
                        {
                            var capture = curMatch.Captures.NamedGroups[i];
                            var grp     = match.Groups [capture.Item1];
                            if (grp == null || grp.Length == 0)
                            {
                                continue;
                            }
                            if (curSegmentOffset < grp.Index)
                            {
                                ReplaceSegment(segments, new ColoredSegment(curSegmentOffset, grp.Index - curSegmentOffset, ScopeStack));
                            }
                            ReplaceSegment(segments, new ColoredSegment(grp.Index, grp.Length, ScopeStack.Push(capture.Item2)));
                            curSegmentOffset = grp.Index + grp.Length;
                        }
                    }

                    if (curMatch.Scope.Count > 0 && curSegmentOffset < matchEndOffset && match.Length > 0)
                    {
                        segments.Add(new ColoredSegment(curSegmentOffset, matchEndOffset - curSegmentOffset, ScopeStack));
                        curSegmentOffset = matchEndOffset;
                    }

                    if (curMatch.Pop)
                    {
                        if (matchEndOffset - curSegmentOffset > 0)
                        {
                            segments.Add(new ColoredSegment(curSegmentOffset, matchEndOffset - curSegmentOffset, ScopeStack));
                        }
                        //if (curMatch.Scope != null)
                        //	scopeStack = scopeStack.Pop ();
                        PopStack(currentContext, curMatch);
                        curSegmentOffset = matchEndOffset;
                    }
                    else if (curMatch.Set != null)
                    {
                        // if (matchEndOffset - curSegmentOffset > 0)
                        //	segments.Add (new ColoredSegment (curSegmentOffset, matchEndOffset - curSegmentOffset, ScopeStack));
                        //if (curMatch.Scope != null)
                        //	scopeStack = scopeStack.Pop ();
                        PopMetaContentScopeStack(currentContext, curMatch);
                        PopStack(currentContext, curMatch);
                        //curSegmentOffset = matchEndOffset;
                        var nextContexts = curMatch.Set.GetContexts(currentContext);
                        PushStack(curMatch, nextContexts);
                        goto skip;
                    }
                    else if (curMatch.Push != null)
                    {
                        var nextContexts = curMatch.Push.GetContexts(currentContext);
                        PushStack(curMatch, nextContexts);
                    }
                    else
                    {
                        if (curMatch.Scope.Count > 0)
                        {
                            for (int i = 0; i < curMatch.Scope.Count; i++)
                            {
                                ScopeStack = ScopeStack.Pop();
                            }
                        }
                    }

                    if (curSegmentOffset < matchEndOffset && match.Length > 0)
                    {
                        segments.Add(new ColoredSegment(curSegmentOffset, matchEndOffset - curSegmentOffset, ScopeStack));
                        curSegmentOffset = matchEndOffset;
                    }
skip:
                    length -= curSegmentOffset - offset;
                    offset  = curSegmentOffset;
                    goto restart;
                }

end:
                if (endOffset - curSegmentOffset > 0)
                {
                    segments.Add(new ColoredSegment(curSegmentOffset, endOffset - curSegmentOffset, ScopeStack));
                }

                return(Task.FromResult(new HighlightedLine(highlightedSegment, segments)));
            }