Пример #1
0
        public static void GetClassifications(SyntaxNode root, int start, int length, bool clipToRange, List <ClassifiedRange> list, CancellationToken cancellationToken)
        {
            var end = start + length;

            // don't let classification ranges escape the requested bounds.
            Action <ClassifiedRange> limiter = range =>
            {
                // only if the classification range overlaps window
                if (range.End > start && range.Start < end)
                {
                    // adjust range it if starts before or ends after the window
                    if (clipToRange && (range.Start < start || range.End > end))
                    {
                        var clipStart = Math.Max(range.Start, start);
                        var clipEnd   = Math.Min(range.End, end);
                        range = new ClassifiedRange(range.Kind, clipStart, clipEnd - clipStart);
                    }

                    // merge ranges if this range is adjacent to the last range and the same kind
                    if (list.Count > 0)
                    {
                        var last = list[list.Count - 1];
                        if (last.Kind == range.Kind &&
                            last.End == range.Start)
                        {
                            list[list.Count - 1] = new ClassifiedRange(last.Kind, last.Start, last.Length + range.Length);
                            return;
                        }
                    }

                    list.Add(range);
                }
            };

            // produce classification ranges for all tokens that coincide with the window
            root.WalkTokens(start, end, token =>
            {
                cancellationToken.ThrowIfCancellationRequested();

                GetTriviaClassifications(token, limiter);

                if (token.IsLiteral && token.Prefix.Length > 0)
                {
                    // special case for literals with prefix
                    limiter(new ClassifiedRange(ClassificationKind.Keyword, token.TextStart, token.Prefix.Length));
                    limiter(new ClassifiedRange(ClassificationKind.Literal, token.TextStart + token.Prefix.Length, token.Text.Length - token.Prefix.Length));
                }
                else
                {
                    var kind = GetKind(token);

                    limiter(new ClassifiedRange(kind, token.TextStart, token.Width));
                }
            });
        }
Пример #2
0
        /// <summary>
        /// Add the two classification ranges together.
        /// If any overlap, classifications from <see cref="P:classifications2"/> take precedence.
        /// </summary>
        protected static IReadOnlyList <ClassifiedRange> Add(
            IReadOnlyList <ClassifiedRange> classifications1,
            IReadOnlyList <ClassifiedRange> classifications2)
        {
            if (classifications2.Count == 0)
            {
                return(classifications1);
            }

            if (classifications1.Count == 0)
            {
                return(classifications2);
            }

            var list = new List <ClassifiedRange>(classifications1.Count + classifications2.Count);

            int             index1 = 0;
            int             index2 = 0;
            ClassifiedRange class1 = null;
            ClassifiedRange class2 = null;

            while (true)
            {
                if (class1 == null && index1 < classifications1.Count)
                {
                    class1 = classifications1[index1];
                }

                if (class2 == null && index2 < classifications2.Count)
                {
                    class2 = classifications2[index2];
                }

                if (class1 == null && class2 == null)
                {
                    // we are done
                    break;
                }
                else if (class1 != null && class2 == null)
                {
                    // no more class2, just add class1
                    list.Add(class1);
                    class1 = null;
                    index1++;
                }
                else if (class2 != null && class1 == null)
                {
                    // no more class1, just add class2
                    list.Add(class2);
                    class2 = null;
                    index2++;
                }
                else if (class1.End < class2.Start)
                {
                    // class1 is entirely before class2, so add class1 and advance it
                    list.Add(class1);
                    class1 = null;
                    index1++;
                }
                else if (class2.End < class1.Start)
                {
                    // class2 is entirely before classs1, so add class2 and advance it
                    list.Add(class2);
                    class2 = null;
                    index2++;
                }
                else if (class1.Start >= class2.Start && class1.End <= class2.End)
                {
                    // class1 is entirely within class2
                    // drop class1 because class2 takes precedence
                    class1 = null;
                    index1++;
                }
                else if (class1.Start < class2.Start)
                {
                    // class1 starts before class2
                    var len = class2.Start - class1.Start;

                    // add the first part off class1
                    list.Add(new ClassifiedRange(class1.Kind, class1.Start, len));

                    if (class1.Length > len)
                    {
                        // adjust class1 for next time around
                        class1 = new ClassifiedRange(class1.Kind, class1.Start + len, class1.Length - len);
                    }
                    else
                    {
                        // advance class1 if no more
                        class1 = null;
                        index1++;
                    }
                }
                else if (class2.Start < class1.Start)
                {
                    // class2 starts before class1
                    var len = class1.Start - class2.Start;

                    // add the first part of class2
                    list.Add(new ClassifiedRange(class2.Kind, class2.Start, len));

                    if (class2.Length > len)
                    {
                        class2 = new ClassifiedRange(class2.Kind, class2.Start + len, class2.Length - len);
                    }
                    else
                    {
                        // advance class2 if no more
                        class2 = null;
                        index2++;
                    }
                }
                else if (class1.End <= class2.End)
                {
                    // both start at same position, class1 ends first
                    // just drop class1, since class2 takes precedence
                    class1 = null;
                    index1++;
                }
                else
                {
                    // both start at same position, class2 ends first
                    var len = class2.Length;

                    // add class2 since it takes precedence
                    list.Add(class2);
                    class2 = null;
                    index2++;

                    // adjust remainder of class1
                    class1 = new ClassifiedRange(class1.Kind, class1.Start + len, class1.Length - len);
                }
            }

            return(list);
        }